cozo-memory 1.0.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 +201 -0
- package/README.md +533 -0
- package/dist/api_bridge.js +266 -0
- package/dist/benchmark-gpu-cpu.js +188 -0
- package/dist/benchmark-heavy.js +230 -0
- package/dist/benchmark.js +160 -0
- package/dist/clear-cache.js +29 -0
- package/dist/db-service.js +228 -0
- package/dist/download-model.js +48 -0
- package/dist/embedding-service.js +249 -0
- package/dist/full-system-test.js +45 -0
- package/dist/hybrid-search.js +337 -0
- package/dist/index.js +3106 -0
- package/dist/inference-engine.js +348 -0
- package/dist/memory-service.js +215 -0
- package/dist/test-advanced-filters.js +64 -0
- package/dist/test-advanced-search.js +82 -0
- package/dist/test-advanced-time.js +47 -0
- package/dist/test-embedding.js +22 -0
- package/dist/test-filter-expr.js +84 -0
- package/dist/test-fts.js +58 -0
- package/dist/test-functions.js +25 -0
- package/dist/test-gpu-check.js +16 -0
- package/dist/test-graph-algs-final.js +76 -0
- package/dist/test-graph-filters.js +88 -0
- package/dist/test-graph-rag.js +124 -0
- package/dist/test-graph-walking.js +138 -0
- package/dist/test-index.js +35 -0
- package/dist/test-int-filter.js +48 -0
- package/dist/test-integration.js +69 -0
- package/dist/test-lower.js +35 -0
- package/dist/test-lsh.js +67 -0
- package/dist/test-mcp-tool.js +40 -0
- package/dist/test-pagerank.js +31 -0
- package/dist/test-semantic-walk.js +145 -0
- package/dist/test-time-filter.js +66 -0
- package/dist/test-time-functions.js +38 -0
- package/dist/test-triggers.js +60 -0
- package/dist/test-ts-ort.js +48 -0
- package/dist/test-validity-access.js +35 -0
- package/dist/test-validity-body.js +42 -0
- package/dist/test-validity-decomp.js +37 -0
- package/dist/test-validity-extraction.js +45 -0
- package/dist/test-validity-json.js +35 -0
- package/dist/test-validity.js +38 -0
- package/dist/types.js +3 -0
- package/dist/verify-gpu.js +30 -0
- package/dist/verify_transaction_tool.js +46 -0
- package/package.json +75 -0
package/README.md
ADDED
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
# CozoDB Memory MCP Server
|
|
2
|
+
|
|
3
|
+
Persistent, local-first memory for AI agents. No cloud, no Docker, no external services – just CozoDB embedded in Node.js.
|
|
4
|
+
|
|
5
|
+
A local, single-user memory system based on CozoDB with MCP (Model Context Protocol) integration. Focus: robust storage, fast hybrid search (Vector/Graph/Keyword), time-travel queries, and maintainable consolidation.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/tobs-code/cozo-memory
|
|
11
|
+
cd cozo-memory
|
|
12
|
+
npm install && npm run build
|
|
13
|
+
npm run start
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Now you can add the server to your MCP client (e.g. Claude Desktop).
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
|
|
20
|
+
This repository contains:
|
|
21
|
+
- An MCP server (stdio) for Claude/other MCP clients.
|
|
22
|
+
- An optional HTTP API bridge server for UI/tools.
|
|
23
|
+
|
|
24
|
+
Key Features:
|
|
25
|
+
- **Hybrid Search (v0.7 Optimized)**: Combination of semantic search (HNSW), **Full-Text Search (FTS)**, and graph signals, merged via Reciprocal Rank Fusion (RRF).
|
|
26
|
+
- **Full-Text Search (FTS)**: Native CozoDB v0.7 FTS indices with stemming, stopword filtering, and robust query sanitizing (cleaning of `+ - * / \ ( ) ? .`) for maximum stability.
|
|
27
|
+
- **Near-Duplicate Detection (LSH)**: Automatically detects very similar observations via MinHash-LSH (CozoDB v0.7) to avoid redundancy.
|
|
28
|
+
- **Recency Bias**: Older content is dampened in fusion (except for explicit keyword searches), so "currently relevant" appears higher more often.
|
|
29
|
+
- **Graph-RAG & Graph-Walking (v1.7 Optimized)**: Advanced retrieval method combining semantic vector seeds with recursive graph traversals. Now uses an optimized **Graph-Walking** algorithm via Datalog, using HNSW index lookups for precise distance calculations during traversal.
|
|
30
|
+
- **Multi-Vector Support (v1.7)**: Each entity now has two specialized vectors:
|
|
31
|
+
1. **Content-Embedding**: Represents the content context (observations).
|
|
32
|
+
2. **Name-Embedding**: Optimized for identification via name/label.
|
|
33
|
+
This significantly improves accuracy when entering graph walks.
|
|
34
|
+
- **Semantic & Persistent Caching (v0.8.5)**: Two-level caching system:
|
|
35
|
+
1. **L1 Memory Cache**: Ultra-fast in-memory LRU cache (< 0.1ms).
|
|
36
|
+
2. **L2 Persistent Cache**: Storage in CozoDB for restart resistance.
|
|
37
|
+
3. **Semantic Matching**: Detects semantically similar queries via vector distance.
|
|
38
|
+
4. **Janitor TTL**: Automatic cleanup of outdated cache entries by the Janitor service.
|
|
39
|
+
- **Time-Travel**: Changes are versioned via CozoDB `Validity`; historical queries are possible.
|
|
40
|
+
- **JSON Merge Operator (++)**: Uses the v0.7 merge operator for efficient, atomic metadata updates.
|
|
41
|
+
- **Multi-Statement Transactions (v1.2)**: Supports atomic transactions across multiple operations using CozoDB block syntax `{ ... }`. Guarantees that related changes (e.g., create entity + add observation + link relationship) are executed fully or not at all.
|
|
42
|
+
- **Graph Metrics & Ranking Boost (v1.3 / v1.6)**: Integrates advanced graph algorithms:
|
|
43
|
+
- **PageRank**: Calculates the "importance" of knowledge nodes for ranking.
|
|
44
|
+
- **Betweenness Centrality**: Identifies central bridge elements in the knowledge network.
|
|
45
|
+
- **HITS (Hubs & Authorities)**: Distinguishes between information sources (Authorities) and pointers (Hubs).
|
|
46
|
+
- **Connected Components**: Detects isolated knowledge islands and subgraphs.
|
|
47
|
+
- These metrics are automatically used in hybrid search (`advancedSearch`) and `graphRag`.
|
|
48
|
+
- **Native CozoDB Operators (v1.5)**: Now uses explicit `:insert`, `:update`, and `:delete` operators instead of generic `:put` (upsert) calls. Increases data safety through strict validation of database states (e.g., error when trying to "insert" an existing entity).
|
|
49
|
+
- **Advanced Time-Travel Analysis (v1.5)**: Extension of relationship history with time range filters (`since`/`until`) and automatic diff summaries to analyze changes (additions/removals) over specific periods.
|
|
50
|
+
- **Graph Features (v1.6)**: Native integration of Shortest Path (Dijkstra) with path reconstruction, Community Detection (LabelPropagation), and advanced centrality measures.
|
|
51
|
+
- **Graph Evolution**: Tracks the temporal development of relationships (e.g., role change from "Manager" to "Consultant") via CozoDB `Validity` queries.
|
|
52
|
+
- **Bridge Discovery**: Identifies "bridge entities" connecting different communities – ideal for creative brainstorming.
|
|
53
|
+
- **Inference**: Implicit suggestions and context extension (e.g., transitive expertise rule).
|
|
54
|
+
- **Conflict Detection (Application-Level & Triggers)**: Automatically detects contradictions in metadata (e.g., "active" vs. "discontinued" / `archived: true`). Uses robust logic in the app layer to ensure data integrity before writing.
|
|
55
|
+
- **Data Integrity (Trigger Concept)**: Prevents invalid states like self-references in relationships (Self-Loops) directly at creation.
|
|
56
|
+
- **Hierarchical Summarization**: The Janitor condenses old fragments into "Executive Summary" nodes to preserve the "Big Picture" long-term.
|
|
57
|
+
- **User Preference Profiling**: A specialized `global_user_profile` entity stores persistent preferences (likes, work style), which receive a **50% score boost** in every search.
|
|
58
|
+
- **All Local**: Embeddings via Transformers/ONNX; no external embedding service required.
|
|
59
|
+
|
|
60
|
+
## Positioning & Comparison
|
|
61
|
+
|
|
62
|
+
Most "Memory" MCP servers fall into two categories:
|
|
63
|
+
1. **Simple Knowledge Graphs**: CRUD operations on triples, often only text search.
|
|
64
|
+
2. **Pure Vector Stores**: Semantic search (RAG), but little understanding of complex relationships.
|
|
65
|
+
|
|
66
|
+
This server fills the gap in between ("Sweet Spot"): A **local, database-backed memory engine** combining vector, graph, and keyword signals.
|
|
67
|
+
|
|
68
|
+
### Comparison with other solutions
|
|
69
|
+
|
|
70
|
+
| Feature | **CozoDB Memory (This Project)** | **Official Reference (`@modelcontextprotocol/server-memory`)** | **mcp-memory-service (Community)** | **Database Adapters (Qdrant/Neo4j)** |
|
|
71
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
72
|
+
| **Backend** | **CozoDB** (Graph + Vector + Relational) | JSON file (`memory.jsonl`) | SQLite / Cloudflare | Specialized DB (only Vector or Graph) |
|
|
73
|
+
| **Search Logic** | **Hybrid (RRF)**: Vector + Keyword + Graph | Keyword only / Exact Graph Match | Vector + Keyword | Mostly only one dimension |
|
|
74
|
+
| **Inference** | **Yes**: Built-in engine for implicit knowledge | No | No ("Dreaming" is consolidation) | No (Retrieval only) |
|
|
75
|
+
| **Time-Travel** | **Yes**: Queries at any point in time (`Validity`) | No (current state only) | History available, no native DB feature | No |
|
|
76
|
+
| **Maintenance** | **Janitor**: LLM-backed cleanup | Manual | Automatic consolidation | Mostly manual |
|
|
77
|
+
| **Deployment** | **Local** (Node.js + Embedded DB) | Local (Docker/NPX) | Local or Cloud | Often requires external DB server |
|
|
78
|
+
|
|
79
|
+
The core advantage is **Retrieval Quality and Traceability**: By combining graph algorithms (PageRank, Community Detection) and vector indices (HNSW), context can be provided much more precisely than through pure similarity search.
|
|
80
|
+
|
|
81
|
+
## Performance & Benchmarks
|
|
82
|
+
|
|
83
|
+
Benchmarks on a standard developer laptop (Windows, Node.js 20+, CPU-only):
|
|
84
|
+
|
|
85
|
+
| Metric | Value | Note |
|
|
86
|
+
| :--- | :--- | :--- |
|
|
87
|
+
| **Graph-Walking (Recursive)** | **~130 ms** | Vector Seed + Recursive Datalog Traversal |
|
|
88
|
+
| **Graph-RAG (Breadth-First)** | **~335 ms** | Vector Seeds + 2-Hop Expansion |
|
|
89
|
+
| **Hybrid Search (Cache Hit)** | **< 0.1 ms** | **v0.8+ Semantic Cache** |
|
|
90
|
+
| **Hybrid Search (Cold)** | **~35 ms** | FTS + HNSW + RRF Fusion |
|
|
91
|
+
| **Vector Search (Raw)** | **~51 ms** | Pure semantic search as reference |
|
|
92
|
+
| **FTS Search (Raw)** | **~12 ms** | Native Full-Text Search Performance |
|
|
93
|
+
| **Ingestion** | **~102 ms** | Per Op (Write + Embedding + FTS/LSH Indexing) |
|
|
94
|
+
| **RAM Usage** | **~1.7 GB** | Primarily due to local `Xenova/bge-m3` model |
|
|
95
|
+
|
|
96
|
+
### Running Benchmarks
|
|
97
|
+
|
|
98
|
+
You can test performance on your system with the integrated benchmark tool:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npm run benchmark
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
This tool (`src/benchmark.ts`) performs the following tests:
|
|
105
|
+
1. **Initialization**: Cold start duration of the server incl. model loading.
|
|
106
|
+
2. **Ingestion**: Mass import of test entities and observations (throughput).
|
|
107
|
+
3. **Search Performance**: Latency measurement for Hybrid Search vs. Raw Vector Search.
|
|
108
|
+
4. **RRF Overhead**: Determination of additional computation time for fusion logic.
|
|
109
|
+
|
|
110
|
+
## Architecture (High Level)
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
┌───────────────────────────┐
|
|
114
|
+
│ MCP Client │
|
|
115
|
+
└──────────────┬────────────┘
|
|
116
|
+
│ stdio
|
|
117
|
+
┌──────────────▼────────────┐
|
|
118
|
+
│ MCP Server │
|
|
119
|
+
│ FastMCP + Zod Schemas │
|
|
120
|
+
└──────────────┬────────────┘
|
|
121
|
+
│
|
|
122
|
+
┌──────────────▼────────────┐
|
|
123
|
+
│ Memory Services │
|
|
124
|
+
│ - Embeddings (ONNX) │
|
|
125
|
+
│ - Hybrid Search (RRF) │
|
|
126
|
+
│ - Semantic LRU Cache │
|
|
127
|
+
│ - Inference Engine │
|
|
128
|
+
└──────────────┬────────────┘
|
|
129
|
+
│
|
|
130
|
+
┌──────────────▼────────────┐
|
|
131
|
+
│ CozoDB (SQLite) │
|
|
132
|
+
│ - Relations + Validity │
|
|
133
|
+
│ - HNSW Indices │
|
|
134
|
+
│ - Datalog/Graph Algorithms│
|
|
135
|
+
└───────────────────────────┘
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Installation
|
|
139
|
+
|
|
140
|
+
### Prerequisites
|
|
141
|
+
- Node.js 20+ (recommended)
|
|
142
|
+
- CozoDB native dependency is installed via `cozo-node`.
|
|
143
|
+
|
|
144
|
+
### Setup
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
npm install
|
|
148
|
+
npm run build
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Windows Quickstart
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
npm install
|
|
155
|
+
npm run build
|
|
156
|
+
npm run start
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Notes:
|
|
160
|
+
- On first start, `@xenova/transformers` downloads the embedding model (may take time).
|
|
161
|
+
- Embeddings are processed on the CPU.
|
|
162
|
+
|
|
163
|
+
## Start / Integration
|
|
164
|
+
|
|
165
|
+
### MCP Server (stdio)
|
|
166
|
+
|
|
167
|
+
The MCP server runs over stdio (for Claude Desktop etc.). Start:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
npm run start
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Default database path: `memory_db.cozo.db` in project root (created automatically).
|
|
174
|
+
|
|
175
|
+
### Claude Desktop Integration
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"mcpServers": {
|
|
180
|
+
"cozo-memory": {
|
|
181
|
+
"command": "node",
|
|
182
|
+
"args": ["C:/Path/to/cozo-memory/dist/index.js"]
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Configuration & Backends
|
|
189
|
+
|
|
190
|
+
The system supports various storage backends. **SQLite** is used by default as it requires no extra installation and offers the best balance of performance and simplicity for most use cases.
|
|
191
|
+
|
|
192
|
+
### Changing Backend (e.g., to RocksDB)
|
|
193
|
+
|
|
194
|
+
RocksDB offers advantages for very large datasets (millions of entries) and write-intensive workloads due to better parallelism and data compression.
|
|
195
|
+
|
|
196
|
+
To change the backend, set the `DB_ENGINE` environment variable before starting:
|
|
197
|
+
|
|
198
|
+
**PowerShell:**
|
|
199
|
+
```powershell
|
|
200
|
+
$env:DB_ENGINE="rocksdb"; npm run dev
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Bash:**
|
|
204
|
+
```bash
|
|
205
|
+
DB_ENGINE=rocksdb npm run dev
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
| Backend | Status | Recommendation |
|
|
209
|
+
| :--- | :--- | :--- |
|
|
210
|
+
| **SQLite** | Active (Default) | Standard for desktop/local usage. |
|
|
211
|
+
| **RocksDB** | Prepared & Tested | For high-performance or very large datasets. |
|
|
212
|
+
| **MDBX** | Not supported | Requires manual build of `cozo-node` from source. |
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Data Model
|
|
217
|
+
|
|
218
|
+
CozoDB Relations (simplified) – all write operations create new `Validity` entries (Time-Travel):
|
|
219
|
+
- `entity`: `id`, `created_at: Validity` ⇒ `name`, `type`, `embedding(1024)`, `name_embedding(1024)`, `metadata(Json)`
|
|
220
|
+
- `observation`: `id`, `created_at: Validity` ⇒ `entity_id`, `text`, `embedding(1024)`, `metadata(Json)`
|
|
221
|
+
- `relationship`: `from_id`, `to_id`, `relation_type`, `created_at: Validity` ⇒ `strength(0..1)`, `metadata(Json)`
|
|
222
|
+
- `entity_community`: `entity_id` ⇒ `community_id` (Key-Value Mapping from LabelPropagation)
|
|
223
|
+
- `memory_snapshot`: `snapshot_id` ⇒ Counts + `metadata` + `created_at(Int)`
|
|
224
|
+
|
|
225
|
+
## MCP Tools
|
|
226
|
+
|
|
227
|
+
The interface is reduced to **4 consolidated tools**. The concrete operation is always chosen via `action`.
|
|
228
|
+
|
|
229
|
+
### mutate_memory (Write)
|
|
230
|
+
|
|
231
|
+
Actions:
|
|
232
|
+
- `create_entity`: `{ name, type, metadata? }`
|
|
233
|
+
- `update_entity`: `{ id, name?, type?, metadata? }`
|
|
234
|
+
- `delete_entity`: `{ entity_id }`
|
|
235
|
+
- `add_observation`: `{ entity_id?, entity_name?, entity_type?, text, metadata? }`
|
|
236
|
+
- `create_relation`: `{ from_id, to_id, relation_type, strength?, metadata? }`
|
|
237
|
+
- `run_transaction`: `{ operations: Array<{ action, params }> }` **(New v1.2)**: Executes multiple operations atomically.
|
|
238
|
+
- `add_inference_rule`: `{ name, datalog }`
|
|
239
|
+
- `ingest_file`: `{ format, content, entity_id?, entity_name?, entity_type?, chunking?, metadata?, observation_metadata?, deduplicate?, max_observations? }`
|
|
240
|
+
|
|
241
|
+
Important Details:
|
|
242
|
+
- `run_transaction` supports `create_entity`, `add_observation`, and `create_relation`. Parameters are automatically suffixed to avoid collisions.
|
|
243
|
+
- `create_relation` rejects self-references (`from_id === to_id`).
|
|
244
|
+
- `strength` is optional and defaults to `1.0`.
|
|
245
|
+
- `add_observation` additionally provides `inferred_suggestions` (suggestions from the Inference Engine).
|
|
246
|
+
- `add_observation` performs deduplication (exact + semantic via LSH). If duplicates are found, returns `status: "duplicate_detected"` with `existing_observation_id` and an estimated `similarity`.
|
|
247
|
+
- `update_entity` uses the JSON Merge Operator `++` (v0.7) to merge existing metadata with new values instead of overwriting them.
|
|
248
|
+
- `add_inference_rule` validates Datalog code upon saving. Invalid syntax or missing required columns result in an error.
|
|
249
|
+
|
|
250
|
+
Examples:
|
|
251
|
+
|
|
252
|
+
```json
|
|
253
|
+
{ "action": "create_entity", "name": "Alice", "type": "Person", "metadata": { "role": "Dev" } }
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
```json
|
|
257
|
+
{ "action": "add_observation", "entity_id": "ENTITY_ID", "text": "Alice is working on the feature flag system." }
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Example (Duplicate):
|
|
261
|
+
|
|
262
|
+
```json
|
|
263
|
+
{ "action": "add_observation", "entity_id": "ENTITY_ID", "text": "Alice is working on the feature flag system." }
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
```json
|
|
267
|
+
{ "status": "duplicate_detected", "existing_observation_id": "OBS_ID", "similarity": 1 }
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
```json
|
|
271
|
+
{ "action": "create_relation", "from_id": "ALICE_ID", "to_id": "PROJ_ID", "relation_type": "works_on", "strength": 1.0 }
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Custom Datalog Rules (Inference):
|
|
275
|
+
|
|
276
|
+
- Inference rules are stored as `action: "add_inference_rule"`.
|
|
277
|
+
- The Datalog query must return a result set with **exactly these 5 columns**: `from_id, to_id, relation_type, confidence, reason`.
|
|
278
|
+
- `$id` is the placeholder for the entity ID for which inference is started.
|
|
279
|
+
|
|
280
|
+
Example (Transitive Manager ⇒ Upper Manager):
|
|
281
|
+
|
|
282
|
+
```json
|
|
283
|
+
{
|
|
284
|
+
"action": "add_inference_rule",
|
|
285
|
+
"name": "upper_manager",
|
|
286
|
+
"datalog": "?[from_id, to_id, relation_type, confidence, reason] :=\n *relationship{from_id: $id, to_id: mid, relation_type: \"manager_of\", @ \"NOW\"},\n *relationship{from_id: mid, to_id: target, relation_type: \"manager_of\", @ \"NOW\"},\n from_id = $id,\n to_id = target,\n relation_type = \"upper_manager_of\",\n confidence = 0.6,\n reason = \"Transitive manager path found\""
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Bulk Ingestion (Markdown/JSON):
|
|
291
|
+
|
|
292
|
+
```json
|
|
293
|
+
{
|
|
294
|
+
"action": "ingest_file",
|
|
295
|
+
"entity_name": "Project Documentation",
|
|
296
|
+
"format": "markdown",
|
|
297
|
+
"chunking": "paragraphs",
|
|
298
|
+
"content": "# Title\n\nSection 1...\n\nSection 2...",
|
|
299
|
+
"deduplicate": true,
|
|
300
|
+
"max_observations": 50
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### query_memory (Read)
|
|
305
|
+
|
|
306
|
+
Actions:
|
|
307
|
+
- `search`: `{ query, limit?, entity_types?, include_entities?, include_observations? }`
|
|
308
|
+
- `advancedSearch`: `{ query, limit?, filters?, graphConstraints?, vectorOptions? }` **(New v1.1 / v1.4)**: Extended search with native HNSW filters (types) and robust post-filtering (metadata, time).
|
|
309
|
+
- `context`: `{ query, context_window?, time_range_hours? }`
|
|
310
|
+
- `entity_details`: `{ entity_id, as_of? }`
|
|
311
|
+
- `history`: `{ entity_id }`
|
|
312
|
+
- `graph_rag`: `{ query, max_depth?, limit?, filters? }` Graph-based reasoning. Finds vector seeds (with inline filtering) first and then expands transitive relationships. Uses recursive Datalog for efficient BFS expansion.
|
|
313
|
+
- `graph_walking`: `{ query, start_entity_id?, max_depth?, limit? }` (v1.7) Recursive semantic graph search. Starts at vector seeds or a specific entity and follows relationships to other semantically relevant entities. Ideal for deeper path exploration.
|
|
314
|
+
- `get_relation_evolution`: `{ from_id, to_id?, since?, until? }` (in `analyze_graph`) Shows temporal development of relationships including time range filter and diff summary.
|
|
315
|
+
|
|
316
|
+
Important Details:
|
|
317
|
+
- `advancedSearch` allows precise filtering:
|
|
318
|
+
- `filters.entityTypes`: List of entity types.
|
|
319
|
+
- `filters.metadata`: Key-Value Map for exact metadata matches.
|
|
320
|
+
- `graphConstraints.requiredRelations`: Only entities having certain relationships.
|
|
321
|
+
- `graphConstraints.targetEntityIds`: Only entities connected to these target IDs.
|
|
322
|
+
- `context` returns a JSON object with entities, observations, graph connections, and inference suggestions.
|
|
323
|
+
- `search` uses RRF (Reciprocal Rank Fusion) to mix vector and keyword signals.
|
|
324
|
+
- `graph_rag` combines vector search with graph-based traversals (default depth 2) for "structured reasoning". Expansion is bidirectional across all relationship types.
|
|
325
|
+
- **User Profiling**: Results linked to the `global_user_profile` entity are automatically preferred (boosted).
|
|
326
|
+
- `time_range_hours` filters candidate results in the time window (in hours, can be float).
|
|
327
|
+
- `as_of` accepts ISO strings or `"NOW"`; invalid format results in an error.
|
|
328
|
+
- If status contradictions are detected, optional `conflict_flag` is attached to entities/observations; `context` additionally provides `conflict_flags` as a summary.
|
|
329
|
+
|
|
330
|
+
Examples:
|
|
331
|
+
|
|
332
|
+
```json
|
|
333
|
+
{ "action": "search", "query": "Feature Flag", "limit": 10 }
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
```json
|
|
337
|
+
{
|
|
338
|
+
"action": "advancedSearch",
|
|
339
|
+
"query": "Manager",
|
|
340
|
+
"filters": { "metadata": { "role": "Lead" } },
|
|
341
|
+
"graphConstraints": { "requiredRelations": ["works_with"] }
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
```json
|
|
346
|
+
{ "action": "graph_rag", "query": "What is Alice working on?", "max_depth": 2 }
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
```json
|
|
350
|
+
{ "action": "context", "query": "What is Alice working on right now?", "context_window": 20 }
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
#### Conflict Detection (Status)
|
|
354
|
+
|
|
355
|
+
If there are contradictory statements about the status of an entity, a conflict is marked. The system considers **temporal consistency**:
|
|
356
|
+
|
|
357
|
+
- **Status Contradiction**: An entity has both "active" and "inactive" status in the **same calendar year**.
|
|
358
|
+
- **Status Change (No Conflict)**: If statements are from different years (e.g., 2024 "discontinued", 2025 "active"), this is interpreted as a legitimate change and **not** marked as a conflict.
|
|
359
|
+
|
|
360
|
+
The detection uses regex matching on keywords like:
|
|
361
|
+
- **Active**: active, running, ongoing, in operation, continued, not discontinued.
|
|
362
|
+
- **Inactive**: discontinued, cancelled, stopped, shut down, closed, deprecated, archived, ended, abandoned.
|
|
363
|
+
|
|
364
|
+
**Integration in API Responses:**
|
|
365
|
+
- `entities[i].conflict_flag` or `observations[i].conflict_flag`: Flag directly on the match.
|
|
366
|
+
- `conflict_flags`: List of all detected conflicts in `context` or `search` result.
|
|
367
|
+
|
|
368
|
+
### analyze_graph (Analysis)
|
|
369
|
+
|
|
370
|
+
Actions:
|
|
371
|
+
- `explore`: `{ start_entity, end_entity?, max_hops?, relation_types? }`
|
|
372
|
+
- with `end_entity`: shortest path (BFS)
|
|
373
|
+
- without `end_entity`: Neighborhood up to max. 5 hops (aggregated by minimal hop count)
|
|
374
|
+
- `communities`: `{}` recalculates communities and writes `entity_community`
|
|
375
|
+
- `pagerank`: `{}` Calculates PageRank scores for all entities.
|
|
376
|
+
- `betweenness`: `{}` Calculates Betweenness Centrality (centrality measure for bridge elements).
|
|
377
|
+
- `hits`: `{}` Calculates HITS scores (Hubs & Authorities).
|
|
378
|
+
- `connected_components`: `{}` Identifies isolated subgraphs.
|
|
379
|
+
- `shortest_path`: `{ start_entity, end_entity }` Calculates shortest path via Dijkstra (incl. distance and path reconstruction).
|
|
380
|
+
- `bridge_discovery`: `{}` Searches for entities acting as bridges between isolated communities (high Betweenness relevance).
|
|
381
|
+
- `semantic_walk`: `{ start_entity, max_depth?, min_similarity? }` (v1.7) Recursive semantic graph search. Starts at an entity and recursively follows paths consisting of explicit relationships AND semantic similarity (vector distance). Finds "associative paths" in the knowledge graph.
|
|
382
|
+
- `hnsw_clusters`: `{}` Analyzes clusters directly on the HNSW graph (Layer 0). Extremely fast as no vector calculations are needed.
|
|
383
|
+
- `infer_relations`: `{ entity_id }` provides suggestions from multiple strategies.
|
|
384
|
+
- `get_relation_evolution`: `{ from_id, to_id?, since?, until? }` shows temporal development of relationships including time range filter and diff summary.
|
|
385
|
+
|
|
386
|
+
Examples:
|
|
387
|
+
|
|
388
|
+
```json
|
|
389
|
+
{ "action": "shortest_path", "start_entity": "ID_A", "end_entity": "ID_B" }
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
```json
|
|
393
|
+
{ "action": "explore", "start_entity": "ENTITY_ID", "max_hops": 3 }
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### manage_system (Maintenance)
|
|
397
|
+
|
|
398
|
+
Actions:
|
|
399
|
+
- `health`: `{}` returns DB counts + embedding cache stats.
|
|
400
|
+
- `snapshot_create`: `{ metadata? }`
|
|
401
|
+
- `snapshot_list`: `{}`
|
|
402
|
+
- `snapshot_diff`: `{ snapshot_id_a, snapshot_id_b }`
|
|
403
|
+
- `cleanup`: `{ confirm, older_than_days?, max_observations?, min_entity_degree?, model? }`
|
|
404
|
+
- `reflect`: `{ entity_id?, model? }` Analyzes memory for contradictions and new insights.
|
|
405
|
+
- `clear_memory`: `{ confirm }`
|
|
406
|
+
|
|
407
|
+
Janitor Cleanup Details:
|
|
408
|
+
- `cleanup` supports `dry_run`: with `confirm: false` only candidates are listed.
|
|
409
|
+
- With `confirm: true`, the Janitor becomes active:
|
|
410
|
+
- **Hierarchical Summarization**: Detects isolated or old observations, has them summarized by a local LLM (Ollama), and creates a new `ExecutiveSummary` node. Old fragments are deleted to reduce noise while preserving knowledge.
|
|
411
|
+
|
|
412
|
+
Reflection Service Details:
|
|
413
|
+
- `reflect` analyzes observations of an entity (or top 5 active entities) to find contradictions, patterns, or temporal developments.
|
|
414
|
+
- Results are persisted as new observations with metadata field `{ "kind": "reflection" }` and are retrievable via `context`.
|
|
415
|
+
- Text is stored with prefix `Reflective Insight: `.
|
|
416
|
+
|
|
417
|
+
Defaults: `older_than_days=30`, `max_observations=20`, `min_entity_degree=2`, `model="demyagent-4b-i1:Q6_K"`.
|
|
418
|
+
|
|
419
|
+
## Technical Highlights
|
|
420
|
+
|
|
421
|
+
### Local ONNX Embeddings (Transformers)
|
|
422
|
+
|
|
423
|
+
Default Model: `Xenova/bge-m3` (1024 dimensions).
|
|
424
|
+
|
|
425
|
+
Embeddings are processed on the CPU to ensure maximum compatibility. They are kept in an LRU cache (1000 entries, 1h TTL). On embedding errors, a zero vector is returned to keep tool calls stable.
|
|
426
|
+
|
|
427
|
+
### Hybrid Search (Vector + Keyword + Graph + Inference) + RRF
|
|
428
|
+
|
|
429
|
+
The search combines:
|
|
430
|
+
- Vector similarity via HNSW indices (`~entity:semantic`, `~observation:semantic`)
|
|
431
|
+
- Keyword matching via Regex (`regex_matches(...)`)
|
|
432
|
+
- Graph signal via PageRank (for central entities)
|
|
433
|
+
- Community Expansion: Entities from the community of top seeds are introduced with a boost
|
|
434
|
+
- Inference signal: probabilistic candidates (e.g., `expert_in`) with `confidence` as score
|
|
435
|
+
|
|
436
|
+
Fusion: Reciprocal Rank Fusion (RRF) across sources `vector`, `keyword`, `graph`, `community`, `inference`.
|
|
437
|
+
|
|
438
|
+
Temporal Decay (active by default):
|
|
439
|
+
- Before RRF fusion, scores are dampened based on time (`created_at`).
|
|
440
|
+
- Half-life: 90 days (exponential decay), with source-specific floors:
|
|
441
|
+
- `keyword`: no decay (corresponds to "explicitly searched")
|
|
442
|
+
- `graph`/`community`: at least 0.6
|
|
443
|
+
- `vector`: at least 0.2
|
|
444
|
+
|
|
445
|
+
Uncertainty/Transparency:
|
|
446
|
+
- Inference candidates are marked as `source: "inference"` and provide a short reason (uncertainty hint) in the result.
|
|
447
|
+
- In `context` output, inferred entities additionally carry an `uncertainty_hint` so an LLM can distinguish "hard fact" vs. "conjecture".
|
|
448
|
+
|
|
449
|
+
### Inference Engine
|
|
450
|
+
|
|
451
|
+
Inference uses multiple strategies (non-persisting):
|
|
452
|
+
- **Co-occurrence**: Entity names in observation texts (`related_to`, confidence 0.7)
|
|
453
|
+
- **Semantic Proximity**: Similar entities via HNSW (`similar_to`, up to max. 0.9)
|
|
454
|
+
- **Transitivity**: A→B and B→C (`potentially_related`, confidence 0.5)
|
|
455
|
+
- **Expertise Rule**: `Person` + `works_on` + `uses_tech` ⇒ `expert_in` (confidence 0.7)
|
|
456
|
+
- **Query-Triggered Expertise**: Search queries with keywords like `expert`, `skill`, `knowledge`, `competence` automatically trigger a dedicated expert search over the graph network.
|
|
457
|
+
|
|
458
|
+
## Optional: HTTP API Bridge
|
|
459
|
+
|
|
460
|
+
### API Bridge
|
|
461
|
+
|
|
462
|
+
For Tools, there is an Express server embedding the `MemoryServer` directly.
|
|
463
|
+
|
|
464
|
+
Start:
|
|
465
|
+
|
|
466
|
+
```bash
|
|
467
|
+
npm run bridge
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
Configuration:
|
|
471
|
+
- Port via `PORT` (Default: `3001`)
|
|
472
|
+
|
|
473
|
+
Selected Endpoints (Prefix `/api`):
|
|
474
|
+
- `GET /entities`, `POST /entities`, `GET /entities/:id`, `DELETE /entities/:id`
|
|
475
|
+
- `POST /observations`
|
|
476
|
+
- `GET /search`, `GET /context`
|
|
477
|
+
- `GET /health`
|
|
478
|
+
- `GET /snapshots`, `POST /snapshots`
|
|
479
|
+
|
|
480
|
+
## Development
|
|
481
|
+
|
|
482
|
+
### Structure
|
|
483
|
+
- `src/index.ts`: MCP Server + Tool Registration + Schema Setup
|
|
484
|
+
- `src/embedding-service.ts`: Embedding Pipeline + LRU Cache
|
|
485
|
+
- `src/hybrid-search.ts`: Search Strategies + RRF + Community Expansion
|
|
486
|
+
- `src/inference-engine.ts`: Inference Strategies
|
|
487
|
+
- `src/api_bridge.ts`: Express API Bridge (for UI)
|
|
488
|
+
|
|
489
|
+
### Scripts (Root)
|
|
490
|
+
- `npm run build`: TypeScript Build
|
|
491
|
+
- `npm run dev`: ts-node Start of MCP Server
|
|
492
|
+
- `npm run start`: Starts `dist/index.js` (stdio)
|
|
493
|
+
- `npm run bridge`: Build + Start of API Bridge (`dist/api_bridge.js`)
|
|
494
|
+
- `npm run benchmark`: Runs performance tests
|
|
495
|
+
|
|
496
|
+
## User Preference Profiling (Mem0-Style)
|
|
497
|
+
|
|
498
|
+
The system maintains a persistent profile of the user (preferences, dislikes, work style) via the specialized entity `global_user_profile`.
|
|
499
|
+
|
|
500
|
+
- **Benefit**: Personalization without manual search ("I know you prefer TypeScript").
|
|
501
|
+
- **Mechanism**: All observations assigned to this entity receive a significant boost in search and context queries.
|
|
502
|
+
- **Initialization**: The profile is automatically created on first start.
|
|
503
|
+
|
|
504
|
+
### Manual Tests
|
|
505
|
+
|
|
506
|
+
There are various test scripts for different features:
|
|
507
|
+
|
|
508
|
+
```bash
|
|
509
|
+
# Tests edge cases and basic operations
|
|
510
|
+
npx ts-node src/test-edge-cases.ts
|
|
511
|
+
|
|
512
|
+
# Tests hybrid search and context retrieval
|
|
513
|
+
npx ts-node src/test-context.ts
|
|
514
|
+
|
|
515
|
+
# Tests memory reflection (requires Ollama)
|
|
516
|
+
npx ts-node test-reflection.ts
|
|
517
|
+
|
|
518
|
+
# Tests user preference profiling and search boost
|
|
519
|
+
npx ts-node test-user-pref.ts
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
## Troubleshooting
|
|
523
|
+
|
|
524
|
+
- Embedding model download may take a long time on first start (Transformers loads artifacts).
|
|
525
|
+
- If `cleanup` is used, an Ollama service must be reachable locally and the desired model must be present.
|
|
526
|
+
|
|
527
|
+
## License
|
|
528
|
+
|
|
529
|
+
This project is licensed under the Apache-2.0 License. See the [LICENSE](LICENSE) file for details.
|
|
530
|
+
|
|
531
|
+
## Disclaimer
|
|
532
|
+
|
|
533
|
+
Single-User, Local-First: This project was developed to work for a single user and a local installation.
|