cozo-memory 1.0.9 โ†’ 1.1.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 CHANGED
@@ -63,6 +63,10 @@ Now you can add the server to your MCP client (e.g. Claude Desktop).
63
63
 
64
64
  ๐Ÿง  **Agentic Retrieval Layer (v2.0)** - Auto-routing engine that analyzes query intent via local LLM to select the optimal search strategy (Vector, Graph, or Community)
65
65
 
66
+ ๐Ÿง  **Multi-Level Memory (v2.0)** - Context-aware memory system with built-in session and task management
67
+
68
+ ๐ŸŽฏ **Tiny Learned Reranker (v2.0)** - Integrated Cross-Encoder model (`ms-marco-MiniLM-L-6-v2`) for ultra-precise re-ranking of top search results
69
+
66
70
  ๐ŸŽฏ **Multi-Vector Support (since v1.7)** - Dual embeddings per entity: content-embedding for context, name-embedding for identification
67
71
 
68
72
  โšก **Semantic Caching (since v0.8.5)** - Two-level cache (L1 memory + L2 persistent) with semantic query matching
@@ -75,7 +79,7 @@ Now you can add the server to your MCP client (e.g. Claude Desktop).
75
79
 
76
80
  ๐Ÿ—๏ธ **Hierarchical GraphRAG (v2.0)** - Automatic generation of thematic "Community Summaries" using local LLMs to enable global "Big Picture" reasoning
77
81
 
78
- ๐Ÿงน **Janitor Service** - LLM-backed automatic cleanup with hierarchical summarization and observation pruning
82
+ ๐Ÿงน **Janitor Service** - LLM-backed automatic cleanup with hierarchical summarization, observation pruning, and **automated session compression**
79
83
 
80
84
  ๐Ÿ‘ค **User Preference Profiling** - Persistent user preferences with automatic 50% search boost
81
85
 
@@ -191,8 +195,10 @@ This tool compares strategies using a synthetic dataset and measures **Recall@K*
191
195
  | Method | Recall@10 | Avg Latency | Best For |
192
196
  | :--- | :--- | :--- | :--- |
193
197
  | **Graph-RAG** | **1.00** | **~32 ms** | Deep relational reasoning |
198
+ | **Graph-RAG (Reranked)** | **1.00** | **~36 ms** | Maximum precision for relational data |
194
199
  | **Graph-Walking** | 1.00 | ~50 ms | Associative path exploration |
195
200
  | **Hybrid Search** | 1.00 | ~89 ms | Broad factual retrieval |
201
+ | **Reranked Search** | 1.00 | ~20 ms* | Ultra-precise factual search (Warm cache) |
196
202
 
197
203
  ## Architecture
198
204
 
@@ -364,6 +370,7 @@ CozoDB Memory includes a full-featured CLI for all operations:
364
370
  # System operations
365
371
  cozo-memory system health
366
372
  cozo-memory system metrics
373
+ cozo-memory system reflect
367
374
 
368
375
  # Entity operations
369
376
  cozo-memory entity create -n "MyEntity" -t "person" -m '{"age": 30}'
@@ -379,11 +386,19 @@ cozo-memory relation create --from <id1> --to <id2> --type "knows" -s 0.8
379
386
  # Search
380
387
  cozo-memory search query -q "search term" -l 10
381
388
  cozo-memory search context -q "context query"
389
+ cozo-memory search agentic -q "agentic query"
382
390
 
383
391
  # Graph operations
384
392
  cozo-memory graph explore -s <entity-id> -h 3
385
393
  cozo-memory graph pagerank
386
394
  cozo-memory graph communities
395
+ cozo-memory graph summarize
396
+
397
+ # Session & Task management
398
+ cozo-memory session start -n "My Session"
399
+ cozo-memory session stop -i <session-id>
400
+ cozo-memory task start -n "My Task" -s <session-id>
401
+ cozo-memory task stop -i <task-id>
387
402
 
388
403
  # Export/Import
389
404
  cozo-memory export json -o backup.json --include-metadata --include-relationships --include-observations
@@ -508,8 +523,8 @@ The interface is reduced to **4 consolidated tools**. The concrete operation is
508
523
 
509
524
  | Tool | Purpose | Key Actions |
510
525
  |------|---------|-------------|
511
- | `mutate_memory` | Write operations | create_entity, update_entity, delete_entity, add_observation, create_relation, run_transaction, add_inference_rule, ingest_file |
512
- | `query_memory` | Read operations | search, advancedSearch, context, entity_details, history, graph_rag, graph_walking, agentic_search |
526
+ | `mutate_memory` | Write operations | create_entity, update_entity, delete_entity, add_observation, create_relation, start_session, stop_session, start_task, stop_task, run_transaction, add_inference_rule, ingest_file |
527
+ | `query_memory` | Read operations | search, advancedSearch, context, entity_details, history, graph_rag, graph_walking, agentic_search (Multi-Level Context support) |
513
528
  | `analyze_graph` | Graph analysis | explore, communities, pagerank, betweenness, hits, shortest_path, bridge_discovery, semantic_walk, infer_relations |
514
529
  | `manage_system` | Maintenance | health, metrics, export_memory, import_memory, snapshot_create, snapshot_list, snapshot_diff, cleanup, reflect, summarize_communities, clear_memory |
515
530
 
@@ -521,6 +536,10 @@ Actions:
521
536
  - `delete_entity`: `{ entity_id }`
522
537
  - `add_observation`: `{ entity_id?, entity_name?, entity_type?, text, metadata? }`
523
538
  - `create_relation`: `{ from_id, to_id, relation_type, strength?, metadata? }`
539
+ - `start_session`: `{ name?, metadata? }` **(New v2.0)**: Starts a new session context (metadata can include `user_id`, `project`, etc.)
540
+ - `stop_session`: `{ session_id }` **(New v2.0)**: Closes/archives an active session.
541
+ - `start_task`: `{ name, session_id?, metadata? }` **(New v2.0)**: Starts a specific task within a session.
542
+ - `stop_task`: `{ task_id }` **(New v2.0)**: Marks a task as completed.
524
543
  - `run_transaction`: `{ operations: Array<{ action, params }> }` **(New v1.2)**: Executes multiple operations atomically.
525
544
  - `add_inference_rule`: `{ name, datalog }`
526
545
  - `ingest_file`: `{ format, file_path?, content?, entity_id?, entity_name?, entity_type?, chunking?, metadata?, observation_metadata?, deduplicate?, max_observations? }`
@@ -608,14 +627,14 @@ PDF Ingestion via File Path:
608
627
  ### query_memory (Read)
609
628
 
610
629
  Actions:
611
- - `search`: `{ query, limit?, entity_types?, include_entities?, include_observations? }`
612
- - `advancedSearch`: `{ query, limit?, filters?, graphConstraints?, vectorOptions? }` **(New v1.1 / v1.4)**: Extended search with native HNSW filters (types) and robust post-filtering (metadata, time).
630
+ - `search`: `{ query, limit?, entity_types?, include_entities?, include_observations?, rerank? }`
631
+ - `advancedSearch`: `{ query, limit?, filters?, graphConstraints?, vectorOptions?, rerank? }`
613
632
  - `context`: `{ query, context_window?, time_range_hours? }`
614
633
  - `entity_details`: `{ entity_id, as_of? }`
615
634
  - `history`: `{ entity_id }`
616
- - `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.
635
+ - `graph_rag`: `{ query, max_depth?, limit?, filters?, rerank? }` Graph-based reasoning. Finds vector seeds (with inline filtering) first and then expands transitive relationships. Uses recursive Datalog for efficient BFS expansion.
617
636
  - `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.
618
- - `agentic_search`: `{ query, limit? }` **(New v2.0)**: **Auto-Routing Search**. Uses a local LLM (Ollama) to analyze query intent and automatically routes it to the most appropriate strategy (`vector_search`, `graph_walk`, or `community_summary`).
637
+ - `agentic_search`: `{ query, limit?, rerank? }` **(New v2.0)**: **Auto-Routing Search**. Uses a local LLM (Ollama) to analyze query intent and automatically routes it to the most appropriate strategy (`vector_search`, `graph_walk`, or `community_summary`).
619
638
  - `get_relation_evolution`: `{ from_id, to_id?, since?, until? }` (in `analyze_graph`) Shows temporal development of relationships including time range filter and diff summary.
620
639
 
621
640
  Important Details:
@@ -717,6 +736,7 @@ Janitor Cleanup Details:
717
736
  - `cleanup` supports `dry_run`: with `confirm: false` only candidates are listed.
718
737
  - With `confirm: true`, the Janitor becomes active:
719
738
  - **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.
739
+ - **Automated Session Compression**: Automatically identifies inactive sessions, summarizes their activity into a few bullet points, and stores the summary in the User Profile while marking the session as archived.
720
740
 
721
741
  **Before Janitor:**
722
742
  ```
@@ -885,6 +905,15 @@ Uncertainty/Transparency:
885
905
  - Inference candidates are marked as `source: "inference"` and provide a short reason (uncertainty hint) in the result.
886
906
  - In `context` output, inferred entities additionally carry an `uncertainty_hint` so an LLM can distinguish "hard fact" vs. "conjecture".
887
907
 
908
+ ### Tiny Learned Reranker (Cross-Encoder)
909
+
910
+ For maximum precision, CozoDB Memory integrates a specialized **Cross-Encoder Reranker** (Phase 2 RAG).
911
+
912
+ - **Model**: `Xenova/ms-marco-MiniLM-L-6-v2` (Local ONNX)
913
+ - **Mechanism**: After initial hybrid retrieval, the top candidates (up to 30) are re-evaluated by the cross-encoder. Unlike bi-encoders (vectors), cross-encoders process query and document simultaneously, capturing deep semantic nuances.
914
+ - **Latency**: Minimal overhead (~4-6ms for top 10 candidates).
915
+ - **Supported Tools**: Available as a `rerank: true` parameter in `search`, `advancedSearch`, `graph_rag`, and `agentic_search`.
916
+
888
917
  ### Inference Engine
889
918
 
890
919
  Inference uses multiple strategies (non-persisting):
@@ -110,6 +110,12 @@ class CLICommands {
110
110
  async advancedSearch(params) {
111
111
  return await this.server.advancedSearch(params);
112
112
  }
113
+ async agenticSearch(query, limit) {
114
+ return await this.server.hybridSearch.agenticRetrieve({
115
+ query,
116
+ limit: limit || 10
117
+ });
118
+ }
113
119
  async context(query, contextWindow, timeRangeHours) {
114
120
  // Use advancedSearch with appropriate parameters
115
121
  return await this.server.advancedSearch({
@@ -146,6 +152,12 @@ class CLICommands {
146
152
  async communities() {
147
153
  return await this.server.recomputeCommunities();
148
154
  }
155
+ async summarizeCommunities(model, minCommunitySize) {
156
+ return await this.server.summarizeCommunities({
157
+ model,
158
+ min_community_size: minCommunitySize
159
+ });
160
+ }
149
161
  // System operations
150
162
  async health() {
151
163
  const entityCount = await this.server.db.run('?[count(id)] := *entity{id, @ "NOW"}');
@@ -162,6 +174,13 @@ class CLICommands {
162
174
  // Access private metrics via type assertion
163
175
  return this.server.metrics;
164
176
  }
177
+ async reflect(entityId, model, mode) {
178
+ return await this.server.reflectMemory({
179
+ entity_id: entityId,
180
+ model,
181
+ mode
182
+ });
183
+ }
165
184
  async exportMemory(format, options) {
166
185
  const { ExportImportService } = await import('./export-import-service.js');
167
186
  // Create a simple wrapper that implements DbService interface
@@ -206,5 +225,18 @@ class CLICommands {
206
225
  async getUserProfile() {
207
226
  return await this.server.editUserProfile({});
208
227
  }
228
+ // Session and Task management
229
+ async startSession(name, metadata) {
230
+ return await this.server.startSession({ name, metadata });
231
+ }
232
+ async stopSession(id) {
233
+ return await this.server.stopSession({ id });
234
+ }
235
+ async startTask(name, sessionId, metadata) {
236
+ return await this.server.startTask({ name, session_id: sessionId, metadata });
237
+ }
238
+ async stopTask(id) {
239
+ return await this.server.stopTask({ id });
240
+ }
209
241
  }
210
242
  exports.CLICommands = CLICommands;
package/dist/cli.js CHANGED
@@ -203,6 +203,23 @@ search
203
203
  handleError(error);
204
204
  }
205
205
  });
206
+ search
207
+ .command('agentic')
208
+ .description('Perform agentic retrieval with automatic routing')
209
+ .requiredOption('-q, --query <query>', 'Search query')
210
+ .option('-l, --limit <number>', 'Result limit', parseInt, 10)
211
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
212
+ .action(async (options) => {
213
+ try {
214
+ await cli.init();
215
+ const result = await cli.agenticSearch(options.query, options.limit);
216
+ formatOutput(result, options.format);
217
+ await cli.close();
218
+ }
219
+ catch (error) {
220
+ handleError(error);
221
+ }
222
+ });
206
223
  // Graph commands
207
224
  const graph = program.command('graph').description('Graph operations');
208
225
  graph
@@ -255,6 +272,23 @@ graph
255
272
  handleError(error);
256
273
  }
257
274
  });
275
+ graph
276
+ .command('summarize')
277
+ .description('Generate hierarchical community summaries (GraphRAG)')
278
+ .option('-m, --model <model>', 'LLM model to use for summaries')
279
+ .option('--min-size <number>', 'Minimum community size', parseInt)
280
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
281
+ .action(async (options) => {
282
+ try {
283
+ await cli.init();
284
+ const result = await cli.summarizeCommunities(options.model, options.minSize);
285
+ formatOutput(result, options.format);
286
+ await cli.close();
287
+ }
288
+ catch (error) {
289
+ handleError(error);
290
+ }
291
+ });
258
292
  // System commands
259
293
  const system = program.command('system').alias('sys').description('System operations');
260
294
  system
@@ -287,6 +321,24 @@ system
287
321
  handleError(error);
288
322
  }
289
323
  });
324
+ system
325
+ .command('reflect')
326
+ .description('Perform self-reflection to discover implicit relations')
327
+ .option('-i, --id <id>', 'Entity ID to reflect on (optional)')
328
+ .option('-m, --model <model>', 'LLM model to use')
329
+ .option('--mode <mode>', 'Reflection mode (summary|discovery)', 'discovery')
330
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
331
+ .action(async (options) => {
332
+ try {
333
+ await cli.init();
334
+ const result = await cli.reflect(options.id, options.model, options.mode);
335
+ formatOutput(result, options.format);
336
+ await cli.close();
337
+ }
338
+ catch (error) {
339
+ handleError(error);
340
+ }
341
+ });
290
342
  // Export/Import commands
291
343
  const exportCmd = program.command('export').description('Export memory');
292
344
  exportCmd
@@ -487,4 +539,77 @@ profile
487
539
  handleError(error);
488
540
  }
489
541
  });
542
+ // Session commands
543
+ const session = program.command('session').description('Session management');
544
+ session
545
+ .command('start')
546
+ .description('Start a new session')
547
+ .option('-n, --name <name>', 'Session name')
548
+ .option('-m, --metadata <json>', 'Metadata as JSON string')
549
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
550
+ .action(async (options) => {
551
+ try {
552
+ await cli.init();
553
+ const metadata = options.metadata ? JSON.parse(options.metadata) : undefined;
554
+ const result = await cli.startSession(options.name, metadata);
555
+ formatOutput(result, options.format);
556
+ await cli.close();
557
+ }
558
+ catch (error) {
559
+ handleError(error);
560
+ }
561
+ });
562
+ session
563
+ .command('stop')
564
+ .description('Stop a session')
565
+ .requiredOption('-i, --id <id>', 'Session ID')
566
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
567
+ .action(async (options) => {
568
+ try {
569
+ await cli.init();
570
+ const result = await cli.stopSession(options.id);
571
+ formatOutput(result, options.format);
572
+ await cli.close();
573
+ }
574
+ catch (error) {
575
+ handleError(error);
576
+ }
577
+ });
578
+ // Task commands
579
+ const task = program.command('task').description('Task management');
580
+ task
581
+ .command('start')
582
+ .description('Start a new task')
583
+ .requiredOption('-n, --name <name>', 'Task name')
584
+ .option('-s, --session-id <id>', 'Session ID')
585
+ .option('-m, --metadata <json>', 'Metadata as JSON string')
586
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
587
+ .action(async (options) => {
588
+ try {
589
+ await cli.init();
590
+ const metadata = options.metadata ? JSON.parse(options.metadata) : undefined;
591
+ const result = await cli.startTask(options.name, options.sessionId, metadata);
592
+ formatOutput(result, options.format);
593
+ await cli.close();
594
+ }
595
+ catch (error) {
596
+ handleError(error);
597
+ }
598
+ });
599
+ task
600
+ .command('stop')
601
+ .description('Stop a task')
602
+ .requiredOption('-i, --id <id>', 'Task ID')
603
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
604
+ .action(async (options) => {
605
+ try {
606
+ await cli.init();
607
+ const result = await cli.stopTask(options.id);
608
+ formatOutput(result, options.format);
609
+ await cli.close();
610
+ }
611
+ catch (error) {
612
+ handleError(error);
613
+ }
614
+ });
490
615
  program.parse();