cozo-memory 1.2.0 → 1.2.2
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/dist/emotional-salience.js +295 -0
- package/dist/index.js +726 -9
- package/dist/memory-activation.js +64 -30
- package/dist/memory-service.js +68 -0
- package/dist/pre-storage-reasoning.js +351 -0
- package/dist/temporal-conflict-resolution.js +10 -6
- package/dist/test-activation-mcp.js +118 -0
- package/dist/test-advanced-search-mcp.js +204 -0
- package/dist/test-conflicts-mcp.js +173 -0
- package/dist/test-emotional-salience.js +177 -0
- package/dist/test-hierarchical-mcp.js +135 -0
- package/dist/test-logical-edges-mcp.js +215 -0
- package/dist/test-metadata-check.js +69 -0
- package/dist/test-metadata-update.js +92 -0
- package/dist/test-pre-storage-reasoning.js +149 -0
- package/dist/test-salience-mcp.js +94 -0
- package/dist/test-spreading-mcp.js +155 -0
- package/dist/test-suggest-connections-mcp.js +172 -0
- package/dist/test-zettelkasten-evolution.js +255 -0
- package/dist/test-zettelkasten-fixed.js +74 -0
- package/dist/test-zettelkasten-live.js +117 -0
- package/dist/test-zettelkasten-mcp.js +96 -0
- package/dist/zettelkasten-evolution.js +342 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -18,6 +18,12 @@ const hybrid_search_1 = require("./hybrid-search");
|
|
|
18
18
|
const inference_engine_1 = require("./inference-engine");
|
|
19
19
|
const dynamic_fusion_1 = require("./dynamic-fusion");
|
|
20
20
|
const adaptive_retrieval_1 = require("./adaptive-retrieval");
|
|
21
|
+
const zettelkasten_evolution_1 = require("./zettelkasten-evolution");
|
|
22
|
+
const memory_activation_1 = require("./memory-activation");
|
|
23
|
+
const emotional_salience_1 = require("./emotional-salience");
|
|
24
|
+
const proactive_suggestions_1 = require("./proactive-suggestions");
|
|
25
|
+
const spreading_activation_1 = require("./spreading-activation");
|
|
26
|
+
const temporal_conflict_resolution_1 = require("./temporal-conflict-resolution");
|
|
21
27
|
exports.DB_PATH = path_1.default.resolve(__dirname, "..", "memory_db.cozo");
|
|
22
28
|
const DB_ENGINE = process.env.DB_ENGINE || "sqlite"; // "sqlite" or "rocksdb"
|
|
23
29
|
exports.USER_ENTITY_ID = "global_user_profile";
|
|
@@ -33,6 +39,15 @@ class MemoryServer {
|
|
|
33
39
|
inferenceEngine;
|
|
34
40
|
initPromise;
|
|
35
41
|
compactionLocks = new Set();
|
|
42
|
+
zettelkastenService = null;
|
|
43
|
+
activationService = null;
|
|
44
|
+
salienceService = null;
|
|
45
|
+
suggestionsService = null;
|
|
46
|
+
spreadingService = null;
|
|
47
|
+
conflictService = null;
|
|
48
|
+
logicalEdgesService = null;
|
|
49
|
+
hierarchicalMemoryService = null;
|
|
50
|
+
queryAwareTraversal = null;
|
|
36
51
|
// Metrics tracking
|
|
37
52
|
metrics = {
|
|
38
53
|
operations: {
|
|
@@ -93,6 +108,143 @@ class MemoryServer {
|
|
|
93
108
|
})();
|
|
94
109
|
this.registerTools();
|
|
95
110
|
}
|
|
111
|
+
getZettelkastenService() {
|
|
112
|
+
if (!this.zettelkastenService) {
|
|
113
|
+
this.zettelkastenService = new zettelkasten_evolution_1.ZettelkastenEvolutionService(this.db, this.embeddingService, {
|
|
114
|
+
enableEvolution: true,
|
|
115
|
+
similarityThreshold: 0.7,
|
|
116
|
+
maxRelatedNotes: 5,
|
|
117
|
+
minKeywordFrequency: 2,
|
|
118
|
+
autoExtractKeywords: true,
|
|
119
|
+
autoBidirectionalLinks: true,
|
|
120
|
+
enrichmentDepth: 'shallow'
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return this.zettelkastenService;
|
|
124
|
+
}
|
|
125
|
+
getActivationService() {
|
|
126
|
+
if (!this.activationService) {
|
|
127
|
+
this.activationService = new memory_activation_1.MemoryActivationService(this.db, {
|
|
128
|
+
initialStrength: 1.0,
|
|
129
|
+
strengthIncrement: 1.0,
|
|
130
|
+
maxStrength: 20.0,
|
|
131
|
+
retentionThreshold: 0.15,
|
|
132
|
+
decayBase: Math.E,
|
|
133
|
+
timeUnit: 'days'
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return this.activationService;
|
|
137
|
+
}
|
|
138
|
+
getSalienceService() {
|
|
139
|
+
if (!this.salienceService) {
|
|
140
|
+
this.salienceService = new emotional_salience_1.EmotionalSalienceService(this.db, {
|
|
141
|
+
enableSalience: true,
|
|
142
|
+
salienceBoostFactor: 2.0,
|
|
143
|
+
decaySlowdownFactor: 0.5,
|
|
144
|
+
minSalienceThreshold: 0.3
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return this.salienceService;
|
|
148
|
+
}
|
|
149
|
+
getSuggestionsService() {
|
|
150
|
+
if (!this.suggestionsService) {
|
|
151
|
+
// Create a minimal DatabaseService wrapper for ProactiveSuggestionsService
|
|
152
|
+
const dbWrapper = {
|
|
153
|
+
getEntity: async (id) => {
|
|
154
|
+
const res = await this.db.run('?[name, type, embedding] := *entity{id: $id, name, type, embedding, @ "NOW"}', { id });
|
|
155
|
+
if (res.rows.length === 0)
|
|
156
|
+
return null;
|
|
157
|
+
return {
|
|
158
|
+
id,
|
|
159
|
+
name: res.rows[0][0],
|
|
160
|
+
type: res.rows[0][1],
|
|
161
|
+
embedding: res.rows[0][2],
|
|
162
|
+
};
|
|
163
|
+
},
|
|
164
|
+
getRelations: async (fromId, toId) => {
|
|
165
|
+
let query = '?[from_id, to_id, relation_type, strength] := *relationship{from_id, to_id, relation_type, strength, @ "NOW"}';
|
|
166
|
+
const params = {};
|
|
167
|
+
if (fromId) {
|
|
168
|
+
query += ', from_id = $from_id';
|
|
169
|
+
params.from_id = fromId;
|
|
170
|
+
}
|
|
171
|
+
if (toId) {
|
|
172
|
+
query += ', to_id = $to_id';
|
|
173
|
+
params.to_id = toId;
|
|
174
|
+
}
|
|
175
|
+
const res = await this.db.run(query, params);
|
|
176
|
+
return res.rows.map((r) => ({
|
|
177
|
+
from_id: r[0],
|
|
178
|
+
to_id: r[1],
|
|
179
|
+
relation_type: r[2],
|
|
180
|
+
strength: r[3],
|
|
181
|
+
}));
|
|
182
|
+
},
|
|
183
|
+
vectorSearchEntity: async (embedding, limit) => {
|
|
184
|
+
const res = await this.db.run(`?[id, name, type, dist] := ~entity:embedding_index{embedding: $embedding | query: $limit, ef: 100, bind_distance: dist}, *entity{id, name, type, @ "NOW"}`, { embedding, limit });
|
|
185
|
+
return res.rows;
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
this.suggestionsService = new proactive_suggestions_1.ProactiveSuggestionsService(dbWrapper, this.embeddingService, {
|
|
189
|
+
maxSuggestions: 10,
|
|
190
|
+
minConfidence: 0.5,
|
|
191
|
+
enableVectorSimilarity: true,
|
|
192
|
+
enableCommonNeighbors: true,
|
|
193
|
+
enableInference: true,
|
|
194
|
+
enableGraphProximity: true
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
return this.suggestionsService;
|
|
198
|
+
}
|
|
199
|
+
getSpreadingService() {
|
|
200
|
+
if (!this.spreadingService) {
|
|
201
|
+
this.spreadingService = new spreading_activation_1.SpreadingActivationService(this.db, this.embeddingService, {
|
|
202
|
+
spreadingFactor: 0.8,
|
|
203
|
+
decayFactor: 0.5,
|
|
204
|
+
temporalDecay: 0.01,
|
|
205
|
+
inhibitionBeta: 0.15,
|
|
206
|
+
inhibitionTopM: 7,
|
|
207
|
+
propagationSteps: 3,
|
|
208
|
+
activationThreshold: 0.01,
|
|
209
|
+
sigmoidGamma: 5.0,
|
|
210
|
+
sigmoidTheta: 0.5
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
return this.spreadingService;
|
|
214
|
+
}
|
|
215
|
+
getConflictService() {
|
|
216
|
+
if (!this.conflictService) {
|
|
217
|
+
this.conflictService = new temporal_conflict_resolution_1.TemporalConflictResolutionService(this.db, this.embeddingService, {
|
|
218
|
+
similarityThreshold: 0.85,
|
|
219
|
+
contradictionThreshold: 0.3,
|
|
220
|
+
timeWindowDays: 365,
|
|
221
|
+
autoResolve: false,
|
|
222
|
+
preserveAuditTrail: true
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
return this.conflictService;
|
|
226
|
+
}
|
|
227
|
+
getLogicalEdgesService() {
|
|
228
|
+
if (!this.logicalEdgesService) {
|
|
229
|
+
const { LogicalEdgesService } = require('./logical-edges-service');
|
|
230
|
+
this.logicalEdgesService = new LogicalEdgesService(this.db);
|
|
231
|
+
}
|
|
232
|
+
return this.logicalEdgesService;
|
|
233
|
+
}
|
|
234
|
+
getHierarchicalMemoryService() {
|
|
235
|
+
if (!this.hierarchicalMemoryService) {
|
|
236
|
+
const { HierarchicalMemoryService } = require('./hierarchical-memory');
|
|
237
|
+
this.hierarchicalMemoryService = new HierarchicalMemoryService(this.db, this.embeddingService);
|
|
238
|
+
}
|
|
239
|
+
return this.hierarchicalMemoryService;
|
|
240
|
+
}
|
|
241
|
+
getQueryAwareTraversal() {
|
|
242
|
+
if (!this.queryAwareTraversal) {
|
|
243
|
+
const { QueryAwareTraversal } = require('./query-aware-traversal');
|
|
244
|
+
this.queryAwareTraversal = new QueryAwareTraversal(this.db, this.embeddingService);
|
|
245
|
+
}
|
|
246
|
+
return this.queryAwareTraversal;
|
|
247
|
+
}
|
|
96
248
|
async janitorCleanup(args) {
|
|
97
249
|
await this.initPromise;
|
|
98
250
|
console.error(`[Janitor] Starting cleanup (auto-compressing sessions first)...`);
|
|
@@ -3213,10 +3365,32 @@ Format MUST start with "ExecutiveSummary: " followed by the consolidated content
|
|
|
3213
3365
|
action: zod_1.z.literal("stop_task"),
|
|
3214
3366
|
id: zod_1.z.string().describe("ID of the task to stop"),
|
|
3215
3367
|
}).passthrough(),
|
|
3368
|
+
zod_1.z.object({
|
|
3369
|
+
action: zod_1.z.literal("enrich_observation"),
|
|
3370
|
+
observation_id: zod_1.z.string().describe("ID of the observation to enrich with Zettelkasten metadata"),
|
|
3371
|
+
}).passthrough(),
|
|
3372
|
+
zod_1.z.object({
|
|
3373
|
+
action: zod_1.z.literal("record_memory_access"),
|
|
3374
|
+
observation_id: zod_1.z.string().describe("ID of the observation to record access for (ACT-R)"),
|
|
3375
|
+
}).passthrough(),
|
|
3376
|
+
zod_1.z.object({
|
|
3377
|
+
action: zod_1.z.literal("prune_weak_memories"),
|
|
3378
|
+
dry_run: zod_1.z.boolean().optional().default(true).describe("If true, only shows candidates without deleting"),
|
|
3379
|
+
entity_id: zod_1.z.string().optional().describe("Optional: Only prune memories for specific entity"),
|
|
3380
|
+
}).passthrough(),
|
|
3381
|
+
zod_1.z.object({
|
|
3382
|
+
action: zod_1.z.literal("detect_conflicts"),
|
|
3383
|
+
entity_id: zod_1.z.string().describe("Entity ID to detect conflicts for"),
|
|
3384
|
+
}),
|
|
3385
|
+
zod_1.z.object({
|
|
3386
|
+
action: zod_1.z.literal("resolve_conflicts"),
|
|
3387
|
+
entity_id: zod_1.z.string().describe("Entity ID to resolve conflicts for"),
|
|
3388
|
+
auto_resolve: zod_1.z.boolean().optional().default(false).describe("Automatically resolve all conflicts"),
|
|
3389
|
+
}),
|
|
3216
3390
|
]);
|
|
3217
3391
|
const MutateMemoryParameters = zod_1.z.object({
|
|
3218
3392
|
action: zod_1.z
|
|
3219
|
-
.enum(["create_entity", "update_entity", "delete_entity", "add_observation", "create_relation", "run_transaction", "add_inference_rule", "ingest_file", "start_session", "stop_session", "start_task", "stop_task", "invalidate_observation", "invalidate_relation"])
|
|
3393
|
+
.enum(["create_entity", "update_entity", "delete_entity", "add_observation", "create_relation", "run_transaction", "add_inference_rule", "ingest_file", "start_session", "stop_session", "start_task", "stop_task", "invalidate_observation", "invalidate_relation", "enrich_observation", "record_memory_access", "prune_weak_memories", "detect_conflicts", "resolve_conflicts"])
|
|
3220
3394
|
.describe("Action (determines which fields are required)"),
|
|
3221
3395
|
name: zod_1.z.string().optional().describe("For create_entity (required) or add_inference_rule (required)"),
|
|
3222
3396
|
type: zod_1.z.string().optional().describe("For create_entity (required)"),
|
|
@@ -3238,7 +3412,8 @@ Format MUST start with "ExecutiveSummary: " followed by the consolidated content
|
|
|
3238
3412
|
relation_type: zod_1.z.string().optional().describe("For create_relation (required)"),
|
|
3239
3413
|
strength: zod_1.z.number().min(0).max(1).optional().describe("Optional for create_relation"),
|
|
3240
3414
|
metadata: MetadataSchema.optional().describe("Optional for create_entity/update_entity/add_observation/create_relation/ingest_file"),
|
|
3241
|
-
observation_id: zod_1.z.string().optional().describe("For invalidate_observation (required)"),
|
|
3415
|
+
observation_id: zod_1.z.string().optional().describe("For invalidate_observation (required) or enrich_observation (required) or record_memory_access (required)"),
|
|
3416
|
+
dry_run: zod_1.z.boolean().optional().describe("For prune_weak_memories: if true, only shows candidates"),
|
|
3242
3417
|
operations: zod_1.z.array(zod_1.z.object({
|
|
3243
3418
|
action: zod_1.z.enum(["create_entity", "add_observation", "create_relation", "delete_entity"]),
|
|
3244
3419
|
params: zod_1.z.any().describe("Parameters for the operation as an object")
|
|
@@ -3271,6 +3446,11 @@ Supported actions:
|
|
|
3271
3446
|
- 'stop_task': Marks a task as completed. Params: { id: string }.
|
|
3272
3447
|
- 'invalidate_observation': Invalidates (soft-deletes) an observation at the current time. Params: { observation_id: string }.
|
|
3273
3448
|
- 'invalidate_relation': Invalidates (soft-deletes) a relationship at the current time. Params: { from_id: string, to_id: string, relation_type: string }.
|
|
3449
|
+
- 'enrich_observation': Manually trigger Zettelkasten enrichment for an observation. Params: { observation_id: string }. Extracts keywords/tags, finds related observations, creates bidirectional links, and updates metadata.
|
|
3450
|
+
- 'record_memory_access': Record access to an observation for ACT-R memory activation tracking. Params: { observation_id: string }. Updates access_count and last_access_time metadata.
|
|
3451
|
+
- 'prune_weak_memories': Delete observations with activation below retention threshold. Params: { dry_run?: boolean (default: true), entity_id?: string }. Returns: { pruned: number, preserved: number, candidates: ActivationScore[] }.
|
|
3452
|
+
- 'detect_conflicts': Detect temporal conflicts for an entity. Params: { entity_id: string }. Returns: { conflicts: [{ older_observation_id, newer_observation_id, conflict_type, confidence, reason }], count }. Detects redundancy, contradictions, and superseded facts.
|
|
3453
|
+
- 'resolve_conflicts': Resolve temporal conflicts by invalidating older observations. Params: { entity_id: string, auto_resolve?: boolean }. Returns: { resolved_conflicts, invalidated_observations, audit_observations }. Creates audit trail if enabled.
|
|
3274
3454
|
|
|
3275
3455
|
Validation: Invalid syntax or missing columns in inference rules will result in errors.`,
|
|
3276
3456
|
parameters: MutateMemoryParameters,
|
|
@@ -3316,6 +3496,117 @@ Validation: Invalid syntax or missing columns in inference rules will result in
|
|
|
3316
3496
|
return JSON.stringify(await this.startTask(rest));
|
|
3317
3497
|
if (action === "stop_task")
|
|
3318
3498
|
return JSON.stringify(await this.stopTask(rest));
|
|
3499
|
+
if (action === "enrich_observation") {
|
|
3500
|
+
try {
|
|
3501
|
+
console.log('[mutate_memory] Enriching observation:', rest.observation_id);
|
|
3502
|
+
// Get observation details
|
|
3503
|
+
const obsRes = await this.db.run(`?[obs_id, entity_id, text, embedding] := *observation{id: $id, entity_id, text, embedding, @ "NOW"}, obs_id = $id`, { id: rest.observation_id });
|
|
3504
|
+
if (obsRes.rows.length === 0) {
|
|
3505
|
+
return JSON.stringify({ error: "Observation not found" });
|
|
3506
|
+
}
|
|
3507
|
+
const [obs_id, entity_id, text, embedding] = obsRes.rows[0];
|
|
3508
|
+
// Enrich the observation
|
|
3509
|
+
const result = await this.getZettelkastenService().enrichObservation(obs_id, text, embedding, entity_id);
|
|
3510
|
+
console.log('[mutate_memory] Observation enriched:', {
|
|
3511
|
+
observation_id: obs_id,
|
|
3512
|
+
keywords: result.extractedKeywords?.length || 0,
|
|
3513
|
+
tags: result.addedTags?.length || 0,
|
|
3514
|
+
links: result.createdLinks || 0
|
|
3515
|
+
});
|
|
3516
|
+
return JSON.stringify(result);
|
|
3517
|
+
}
|
|
3518
|
+
catch (error) {
|
|
3519
|
+
console.error('[mutate_memory] Error enriching observation:', error);
|
|
3520
|
+
return JSON.stringify({
|
|
3521
|
+
error: "Failed to enrich observation",
|
|
3522
|
+
details: error.message
|
|
3523
|
+
});
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
if (action === "record_memory_access") {
|
|
3527
|
+
try {
|
|
3528
|
+
console.log('[mutate_memory] Recording memory access:', rest.observation_id);
|
|
3529
|
+
await this.getActivationService().recordAccess(rest.observation_id);
|
|
3530
|
+
console.log('[mutate_memory] Memory access recorded successfully');
|
|
3531
|
+
return JSON.stringify({
|
|
3532
|
+
success: true,
|
|
3533
|
+
observation_id: rest.observation_id,
|
|
3534
|
+
message: "Access recorded successfully"
|
|
3535
|
+
});
|
|
3536
|
+
}
|
|
3537
|
+
catch (error) {
|
|
3538
|
+
console.error('[mutate_memory] Error recording memory access:', error);
|
|
3539
|
+
return JSON.stringify({
|
|
3540
|
+
error: "Failed to record memory access",
|
|
3541
|
+
details: error.message
|
|
3542
|
+
});
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3545
|
+
if (action === "prune_weak_memories") {
|
|
3546
|
+
try {
|
|
3547
|
+
const dryRun = rest.dry_run !== false; // Default to true
|
|
3548
|
+
console.log('[mutate_memory] Pruning weak memories:', {
|
|
3549
|
+
dry_run: dryRun,
|
|
3550
|
+
entity_id: rest.entity_id || 'all'
|
|
3551
|
+
});
|
|
3552
|
+
const result = await this.getActivationService().pruneWeakMemories(dryRun, rest.entity_id);
|
|
3553
|
+
console.log('[mutate_memory] Prune completed:', {
|
|
3554
|
+
pruned: result.pruned,
|
|
3555
|
+
preserved: result.preserved,
|
|
3556
|
+
candidates: result.candidates.length
|
|
3557
|
+
});
|
|
3558
|
+
return JSON.stringify(result);
|
|
3559
|
+
}
|
|
3560
|
+
catch (error) {
|
|
3561
|
+
console.error('[mutate_memory] Error pruning weak memories:', error);
|
|
3562
|
+
return JSON.stringify({
|
|
3563
|
+
error: "Failed to prune weak memories",
|
|
3564
|
+
details: error.message
|
|
3565
|
+
});
|
|
3566
|
+
}
|
|
3567
|
+
}
|
|
3568
|
+
if (action === "detect_conflicts") {
|
|
3569
|
+
try {
|
|
3570
|
+
console.log('[mutate_memory] Detecting conflicts for entity:', rest.entity_id);
|
|
3571
|
+
const conflicts = await this.getConflictService().detectConflicts(rest.entity_id);
|
|
3572
|
+
console.log('[mutate_memory] Conflict detection completed:', {
|
|
3573
|
+
entity_id: rest.entity_id,
|
|
3574
|
+
conflicts_found: conflicts.length
|
|
3575
|
+
});
|
|
3576
|
+
return JSON.stringify({
|
|
3577
|
+
entity_id: rest.entity_id,
|
|
3578
|
+
conflicts,
|
|
3579
|
+
count: conflicts.length
|
|
3580
|
+
});
|
|
3581
|
+
}
|
|
3582
|
+
catch (error) {
|
|
3583
|
+
console.error('[mutate_memory] Error detecting conflicts:', error);
|
|
3584
|
+
return JSON.stringify({
|
|
3585
|
+
error: "Failed to detect conflicts",
|
|
3586
|
+
details: error.message
|
|
3587
|
+
});
|
|
3588
|
+
}
|
|
3589
|
+
}
|
|
3590
|
+
if (action === "resolve_conflicts") {
|
|
3591
|
+
try {
|
|
3592
|
+
console.log('[mutate_memory] Resolving conflicts for entity:', rest.entity_id);
|
|
3593
|
+
const result = await this.getConflictService().resolveConflicts(rest.entity_id);
|
|
3594
|
+
console.log('[mutate_memory] Conflict resolution completed:', {
|
|
3595
|
+
entity_id: rest.entity_id,
|
|
3596
|
+
resolved: result.resolved_conflicts,
|
|
3597
|
+
invalidated: result.invalidated_observations.length,
|
|
3598
|
+
audit_trail: result.audit_observations.length
|
|
3599
|
+
});
|
|
3600
|
+
return JSON.stringify(result);
|
|
3601
|
+
}
|
|
3602
|
+
catch (error) {
|
|
3603
|
+
console.error('[mutate_memory] Error resolving conflicts:', error);
|
|
3604
|
+
return JSON.stringify({
|
|
3605
|
+
error: "Failed to resolve conflicts",
|
|
3606
|
+
details: error.message
|
|
3607
|
+
});
|
|
3608
|
+
}
|
|
3609
|
+
}
|
|
3319
3610
|
return JSON.stringify({ error: "Unknown action" });
|
|
3320
3611
|
},
|
|
3321
3612
|
});
|
|
@@ -3441,10 +3732,48 @@ Validation: Invalid syntax or missing columns in inference rules will result in
|
|
|
3441
3732
|
query: zod_1.z.string().describe("Search query for adaptive retrieval"),
|
|
3442
3733
|
limit: zod_1.z.number().optional().default(10).describe("Maximum number of results"),
|
|
3443
3734
|
}),
|
|
3735
|
+
zod_1.z.object({
|
|
3736
|
+
action: zod_1.z.literal("get_zettelkasten_stats"),
|
|
3737
|
+
}),
|
|
3738
|
+
zod_1.z.object({
|
|
3739
|
+
action: zod_1.z.literal("get_activation_stats"),
|
|
3740
|
+
entity_id: zod_1.z.string().optional().describe("Optional: Filter by entity ID"),
|
|
3741
|
+
}),
|
|
3742
|
+
zod_1.z.object({
|
|
3743
|
+
action: zod_1.z.literal("get_salience_stats"),
|
|
3744
|
+
}),
|
|
3745
|
+
zod_1.z.object({
|
|
3746
|
+
action: zod_1.z.literal("suggest_connections"),
|
|
3747
|
+
entity_id: zod_1.z.string().describe("Entity ID to suggest connections for"),
|
|
3748
|
+
max_suggestions: zod_1.z.number().optional().default(10).describe("Maximum number of suggestions"),
|
|
3749
|
+
min_confidence: zod_1.z.number().min(0).max(1).optional().default(0.5).describe("Minimum confidence threshold"),
|
|
3750
|
+
}),
|
|
3751
|
+
zod_1.z.object({
|
|
3752
|
+
action: zod_1.z.literal("spreading_activation"),
|
|
3753
|
+
query: zod_1.z.string().describe("Search query for spreading activation"),
|
|
3754
|
+
seed_top_k: zod_1.z.number().optional().default(5).describe("Number of seed nodes to start from"),
|
|
3755
|
+
limit: zod_1.z.number().optional().default(30).describe("Maximum number of results"),
|
|
3756
|
+
}),
|
|
3757
|
+
zod_1.z.object({
|
|
3758
|
+
action: zod_1.z.literal("qafd_search"),
|
|
3759
|
+
query: zod_1.z.string().describe("Search query for QAFD (Query-Aware Flow Diffusion)"),
|
|
3760
|
+
seed_top_k: zod_1.z.number().optional().default(5).describe("Number of vector seeds"),
|
|
3761
|
+
max_hops: zod_1.z.number().min(1).max(3).optional().default(2).describe("Maximum traversal depth"),
|
|
3762
|
+
damping_factor: zod_1.z.number().min(0).max(1).optional().default(0.85).describe("Flow diffusion damping factor"),
|
|
3763
|
+
min_score: zod_1.z.number().min(0).max(1).optional().default(0.05).describe("Minimum relevance threshold"),
|
|
3764
|
+
limit: zod_1.z.number().optional().default(10).describe("Maximum number of results"),
|
|
3765
|
+
}),
|
|
3766
|
+
zod_1.z.object({
|
|
3767
|
+
action: zod_1.z.literal("hierarchical_memory_query"),
|
|
3768
|
+
query: zod_1.z.string().describe("Search query for hierarchical memory"),
|
|
3769
|
+
entity_id: zod_1.z.string().optional().describe("Optional: Filter by entity ID"),
|
|
3770
|
+
levels: zod_1.z.array(zod_1.z.number().min(0).max(3)).optional().describe("Memory levels to query (0-3)"),
|
|
3771
|
+
limit: zod_1.z.number().optional().default(10).describe("Maximum number of results"),
|
|
3772
|
+
}),
|
|
3444
3773
|
]);
|
|
3445
3774
|
const QueryMemoryParameters = zod_1.z.object({
|
|
3446
3775
|
action: zod_1.z
|
|
3447
|
-
.enum(["search", "advancedSearch", "context", "entity_details", "history", "graph_rag", "graph_walking", "agentic_search", "dynamic_fusion", "adaptive_retrieval"])
|
|
3776
|
+
.enum(["search", "advancedSearch", "context", "entity_details", "history", "graph_rag", "graph_walking", "agentic_search", "dynamic_fusion", "adaptive_retrieval", "get_zettelkasten_stats", "get_activation_stats", "get_salience_stats", "suggest_connections", "spreading_activation", "qafd_search", "hierarchical_memory_query"])
|
|
3448
3777
|
.describe("Action (determines which fields are required)"),
|
|
3449
3778
|
query: zod_1.z.string().optional().describe("Required for search/advancedSearch/context/graph_rag/graph_walking/agentic_search/dynamic_fusion/adaptive_retrieval"),
|
|
3450
3779
|
limit: zod_1.z.number().optional().describe("Only for search/advancedSearch/graph_rag/graph_walking/dynamic_fusion/adaptive_retrieval"),
|
|
@@ -3481,6 +3810,11 @@ Supported actions:
|
|
|
3481
3810
|
- 'agentic_search': Auto-Routing Search. Uses local LLM to analyze intent and routes the query automatically to the best strategy (Vector, Graph, or Community Summaries). Params: { query: string, limit?: number }.
|
|
3482
3811
|
- 'adaptive_retrieval': GraphRAG-R1 inspired adaptive retrieval with Progressive Retrieval Attenuation (PRA) and Cost-Aware F1 (CAF) scoring. Automatically selects optimal strategy based on query complexity and historical performance. Params: { query: string, limit?: number }.
|
|
3483
3812
|
- 'dynamic_fusion': Advanced multi-path fusion search combining Vector (HNSW), Sparse (keyword), FTS (full-text), and Graph traversal with configurable weights and strategies. Params: { query: string, config?: { vector?, sparse?, fts?, graph?, fusion? }, limit?: number }. Each path can be enabled/disabled and weighted independently. Fusion strategies: 'rrf' (Reciprocal Rank Fusion), 'weighted_sum', 'max', 'adaptive'. Returns results with path contribution details and performance stats.
|
|
3813
|
+
- 'get_zettelkasten_stats': Get Zettelkasten Memory Evolution statistics. No params required. Returns: { totalObservations, enrichedObservations, totalLinks, averageLinksPerNote, topKeywords, topTags, connectionTypes }.
|
|
3814
|
+
- 'get_activation_stats': Get ACT-R Memory Activation statistics. Params: { entity_id?: string }. Returns: { totalObservations, averageActivation, averageStrength, belowThreshold, aboveThreshold, distribution }.
|
|
3815
|
+
- 'get_salience_stats': Get Emotional Salience statistics. No params required. Returns: { totalObservations, withSalience, distribution, averageSalience, topKeywords }.
|
|
3816
|
+
- 'suggest_connections': Proactive connection suggestions for an entity. Params: { entity_id: string, max_suggestions?: number, min_confidence?: number }. Returns: { entity_id, suggestions: [{ entity_id, entity_name, entity_type, source, confidence, confidence_level, reason, metadata }], count }. Combines vector similarity, common neighbors, graph proximity, and inference strategies.
|
|
3817
|
+
- 'spreading_activation': SYNAPSE spreading activation search. Params: { query: string, seed_top_k?: number, limit?: number }. Returns: { scores: [{ entityId, activation, potential, source, hops }], iterations, converged, seedNodes }. Implements neural-inspired activation spreading with fan effect, lateral inhibition, and sigmoid activation.
|
|
3484
3818
|
|
|
3485
3819
|
Notes: 'adaptive_retrieval' learns from usage and optimizes over time. 'dynamic_fusion' provides the most control and transparency over retrieval paths. 'agentic_search' is the most adaptive. 'context' is ideal for exploratory questions. 'search' and 'advancedSearch' are better for targeted fact retrieval.`,
|
|
3486
3820
|
parameters: QueryMemoryParameters,
|
|
@@ -3748,6 +4082,214 @@ Notes: 'adaptive_retrieval' learns from usage and optimizes over time. 'dynamic_
|
|
|
3748
4082
|
});
|
|
3749
4083
|
}
|
|
3750
4084
|
}
|
|
4085
|
+
if (input.action === "get_zettelkasten_stats") {
|
|
4086
|
+
try {
|
|
4087
|
+
console.log('[query_memory] Getting Zettelkasten stats');
|
|
4088
|
+
const stats = await this.getZettelkastenService().getEvolutionStats();
|
|
4089
|
+
console.log('[query_memory] Zettelkasten stats retrieved:', {
|
|
4090
|
+
totalObservations: stats.totalObservations,
|
|
4091
|
+
enrichedObservations: stats.enrichedObservations,
|
|
4092
|
+
totalLinks: stats.totalLinks,
|
|
4093
|
+
averageLinksPerNote: stats.averageLinksPerNote.toFixed(2)
|
|
4094
|
+
});
|
|
4095
|
+
return JSON.stringify(stats);
|
|
4096
|
+
}
|
|
4097
|
+
catch (error) {
|
|
4098
|
+
console.error('[query_memory] Error getting Zettelkasten stats:', error);
|
|
4099
|
+
return JSON.stringify({
|
|
4100
|
+
error: "Failed to get Zettelkasten stats",
|
|
4101
|
+
details: error.message
|
|
4102
|
+
});
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
if (input.action === "get_activation_stats") {
|
|
4106
|
+
try {
|
|
4107
|
+
console.log('[query_memory] Getting ACT-R activation stats', input.entity_id ? `for entity ${input.entity_id}` : '(all entities)');
|
|
4108
|
+
const stats = await this.getActivationService().getActivationStats(input.entity_id);
|
|
4109
|
+
console.log('[query_memory] Activation stats retrieved:', {
|
|
4110
|
+
totalObservations: stats.totalObservations,
|
|
4111
|
+
averageActivation: stats.averageActivation.toFixed(3),
|
|
4112
|
+
belowThreshold: stats.belowThreshold,
|
|
4113
|
+
aboveThreshold: stats.aboveThreshold
|
|
4114
|
+
});
|
|
4115
|
+
return JSON.stringify(stats);
|
|
4116
|
+
}
|
|
4117
|
+
catch (error) {
|
|
4118
|
+
console.error('[query_memory] Error getting activation stats:', error);
|
|
4119
|
+
return JSON.stringify({
|
|
4120
|
+
error: "Failed to get activation stats",
|
|
4121
|
+
details: error.message
|
|
4122
|
+
});
|
|
4123
|
+
}
|
|
4124
|
+
}
|
|
4125
|
+
if (input.action === "get_salience_stats") {
|
|
4126
|
+
try {
|
|
4127
|
+
console.log('[query_memory] Getting Emotional Salience stats');
|
|
4128
|
+
const stats = await this.getSalienceService().getSalienceStats();
|
|
4129
|
+
console.log('[query_memory] Salience stats retrieved:', {
|
|
4130
|
+
totalObservations: stats.totalObservations,
|
|
4131
|
+
withSalience: stats.withSalience,
|
|
4132
|
+
averageSalience: stats.averageSalience.toFixed(3)
|
|
4133
|
+
});
|
|
4134
|
+
return JSON.stringify(stats);
|
|
4135
|
+
}
|
|
4136
|
+
catch (error) {
|
|
4137
|
+
console.error('[query_memory] Error getting salience stats:', error);
|
|
4138
|
+
return JSON.stringify({
|
|
4139
|
+
error: "Failed to get salience stats",
|
|
4140
|
+
details: error.message
|
|
4141
|
+
});
|
|
4142
|
+
}
|
|
4143
|
+
}
|
|
4144
|
+
if (input.action === "suggest_connections") {
|
|
4145
|
+
try {
|
|
4146
|
+
console.log('[query_memory] Suggesting connections for entity:', input.entity_id);
|
|
4147
|
+
const service = this.getSuggestionsService();
|
|
4148
|
+
// Update config if custom parameters provided
|
|
4149
|
+
if (input.max_suggestions || input.min_confidence) {
|
|
4150
|
+
service.updateConfig({
|
|
4151
|
+
maxSuggestions: input.max_suggestions,
|
|
4152
|
+
minConfidence: input.min_confidence
|
|
4153
|
+
});
|
|
4154
|
+
}
|
|
4155
|
+
const suggestions = await service.suggestConnections(input.entity_id);
|
|
4156
|
+
console.log('[query_memory] Found', suggestions.length, 'connection suggestions');
|
|
4157
|
+
return JSON.stringify({
|
|
4158
|
+
entity_id: input.entity_id,
|
|
4159
|
+
suggestions,
|
|
4160
|
+
count: suggestions.length
|
|
4161
|
+
});
|
|
4162
|
+
}
|
|
4163
|
+
catch (error) {
|
|
4164
|
+
console.error('[query_memory] Error suggesting connections:', error);
|
|
4165
|
+
return JSON.stringify({
|
|
4166
|
+
error: "Failed to suggest connections",
|
|
4167
|
+
details: error.message
|
|
4168
|
+
});
|
|
4169
|
+
}
|
|
4170
|
+
}
|
|
4171
|
+
if (input.action === "spreading_activation") {
|
|
4172
|
+
try {
|
|
4173
|
+
console.log('[query_memory] Spreading activation search:', input.query);
|
|
4174
|
+
const result = await this.getSpreadingService().spreadActivation(input.query, input.seed_top_k || 5);
|
|
4175
|
+
// Limit results if requested
|
|
4176
|
+
const limitedScores = input.limit
|
|
4177
|
+
? result.scores.slice(0, input.limit)
|
|
4178
|
+
: result.scores;
|
|
4179
|
+
console.log('[query_memory] Spreading activation completed:', {
|
|
4180
|
+
totalScores: result.scores.length,
|
|
4181
|
+
returned: limitedScores.length,
|
|
4182
|
+
iterations: result.iterations,
|
|
4183
|
+
converged: result.converged
|
|
4184
|
+
});
|
|
4185
|
+
return JSON.stringify({
|
|
4186
|
+
scores: limitedScores,
|
|
4187
|
+
iterations: result.iterations,
|
|
4188
|
+
converged: result.converged,
|
|
4189
|
+
seedNodes: result.seedNodes,
|
|
4190
|
+
totalResults: result.scores.length
|
|
4191
|
+
});
|
|
4192
|
+
}
|
|
4193
|
+
catch (error) {
|
|
4194
|
+
console.error('[query_memory] Error in spreading activation:', error);
|
|
4195
|
+
return JSON.stringify({
|
|
4196
|
+
error: "Failed to perform spreading activation",
|
|
4197
|
+
details: error.message
|
|
4198
|
+
});
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4201
|
+
if (input.action === "qafd_search") {
|
|
4202
|
+
try {
|
|
4203
|
+
console.log('[query_memory] QAFD search:', input.query);
|
|
4204
|
+
const result = await this.getQueryAwareTraversal().hybridSearch(input.query, {
|
|
4205
|
+
seedTopK: input.seed_top_k || 5,
|
|
4206
|
+
maxHops: input.max_hops || 2,
|
|
4207
|
+
dampingFactor: input.damping_factor || 0.85,
|
|
4208
|
+
minScore: input.min_score || 0.05,
|
|
4209
|
+
topK: input.limit || 10
|
|
4210
|
+
});
|
|
4211
|
+
console.log('[query_memory] QAFD search completed:', {
|
|
4212
|
+
totalResults: result.length
|
|
4213
|
+
});
|
|
4214
|
+
return JSON.stringify({
|
|
4215
|
+
results: result,
|
|
4216
|
+
count: result.length
|
|
4217
|
+
});
|
|
4218
|
+
}
|
|
4219
|
+
catch (error) {
|
|
4220
|
+
console.error('[query_memory] Error in QAFD search:', error);
|
|
4221
|
+
return JSON.stringify({
|
|
4222
|
+
error: "Failed to perform QAFD search",
|
|
4223
|
+
details: error.message
|
|
4224
|
+
});
|
|
4225
|
+
}
|
|
4226
|
+
}
|
|
4227
|
+
if (input.action === "hierarchical_memory_query") {
|
|
4228
|
+
try {
|
|
4229
|
+
console.log('[query_memory] Hierarchical memory query:', input.query);
|
|
4230
|
+
// Build query filter for memory levels
|
|
4231
|
+
let levelFilter = '';
|
|
4232
|
+
if (input.levels && input.levels.length > 0) {
|
|
4233
|
+
const levelConditions = input.levels.map((l) => `memory_level = ${l}`).join(' or ');
|
|
4234
|
+
levelFilter = `, (${levelConditions})`;
|
|
4235
|
+
}
|
|
4236
|
+
// Build entity filter
|
|
4237
|
+
let entityFilter = '';
|
|
4238
|
+
if (input.entity_id) {
|
|
4239
|
+
entityFilter = `, entity_id = $entity_id`;
|
|
4240
|
+
}
|
|
4241
|
+
// Query observations with level filtering
|
|
4242
|
+
const queryEmbedding = await this.embeddingService.embed(input.query);
|
|
4243
|
+
const datalog = `
|
|
4244
|
+
?[id, entity_id, text, memory_level, dist] :=
|
|
4245
|
+
~observation:semantic{
|
|
4246
|
+
id |
|
|
4247
|
+
query: vec($embedding),
|
|
4248
|
+
k: $limit,
|
|
4249
|
+
ef: 100,
|
|
4250
|
+
bind_distance: dist
|
|
4251
|
+
},
|
|
4252
|
+
*observation{id, entity_id, text, metadata, @ "NOW"},
|
|
4253
|
+
memory_level = get(metadata, "memory_level", 0)
|
|
4254
|
+
${levelFilter}
|
|
4255
|
+
${entityFilter}
|
|
4256
|
+
|
|
4257
|
+
:order dist
|
|
4258
|
+
`;
|
|
4259
|
+
const params = {
|
|
4260
|
+
embedding: queryEmbedding,
|
|
4261
|
+
limit: input.limit || 10
|
|
4262
|
+
};
|
|
4263
|
+
if (input.entity_id) {
|
|
4264
|
+
params.entity_id = input.entity_id;
|
|
4265
|
+
}
|
|
4266
|
+
const result = await this.db.run(datalog, params);
|
|
4267
|
+
const observations = result.rows.map((r) => ({
|
|
4268
|
+
id: r[0],
|
|
4269
|
+
entity_id: r[1],
|
|
4270
|
+
text: r[2],
|
|
4271
|
+
memory_level: r[3],
|
|
4272
|
+
distance: r[4]
|
|
4273
|
+
}));
|
|
4274
|
+
console.log('[query_memory] Hierarchical memory query completed:', {
|
|
4275
|
+
totalResults: observations.length
|
|
4276
|
+
});
|
|
4277
|
+
return JSON.stringify({
|
|
4278
|
+
results: observations,
|
|
4279
|
+
count: observations.length,
|
|
4280
|
+
query: input.query,
|
|
4281
|
+
levels: input.levels || [0, 1, 2, 3],
|
|
4282
|
+
entity_id: input.entity_id
|
|
4283
|
+
});
|
|
4284
|
+
}
|
|
4285
|
+
catch (error) {
|
|
4286
|
+
console.error('[query_memory] Error in hierarchical memory query:', error);
|
|
4287
|
+
return JSON.stringify({
|
|
4288
|
+
error: "Failed to perform hierarchical memory query",
|
|
4289
|
+
details: error.message
|
|
4290
|
+
});
|
|
4291
|
+
}
|
|
4292
|
+
}
|
|
3751
4293
|
if (input.action === "graph_rag") {
|
|
3752
4294
|
if (!input.query || input.query.trim().length === 0) {
|
|
3753
4295
|
return JSON.stringify({ error: "Search query must not be empty." });
|
|
@@ -3894,16 +4436,28 @@ Notes: 'adaptive_retrieval' learns from usage and optimizes over time. 'dynamic_
|
|
|
3894
4436
|
zod_1.z.object({
|
|
3895
4437
|
action: zod_1.z.literal("hnsw_clusters"),
|
|
3896
4438
|
}),
|
|
4439
|
+
zod_1.z.object({
|
|
4440
|
+
action: zod_1.z.literal("discover_logical_edges"),
|
|
4441
|
+
entity_id: zod_1.z.string().describe("ID of the entity to discover logical edges for"),
|
|
4442
|
+
}),
|
|
4443
|
+
zod_1.z.object({
|
|
4444
|
+
action: zod_1.z.literal("materialize_logical_edges"),
|
|
4445
|
+
entity_id: zod_1.z.string().describe("ID of the entity to materialize logical edges for"),
|
|
4446
|
+
}),
|
|
4447
|
+
zod_1.z.object({
|
|
4448
|
+
action: zod_1.z.literal("detect_temporal_patterns"),
|
|
4449
|
+
entity_id: zod_1.z.string().describe("ID of the entity to detect temporal patterns for"),
|
|
4450
|
+
}),
|
|
3897
4451
|
]);
|
|
3898
4452
|
const AnalyzeGraphParameters = zod_1.z.object({
|
|
3899
4453
|
action: zod_1.z
|
|
3900
|
-
.enum(["explore", "communities", "pagerank", "betweenness", "hits", "connected_components", "shortest_path", "bridge_discovery", "infer_relations", "get_relation_evolution", "semantic_walk", "hnsw_clusters"])
|
|
4454
|
+
.enum(["explore", "communities", "pagerank", "betweenness", "hits", "connected_components", "shortest_path", "bridge_discovery", "infer_relations", "get_relation_evolution", "semantic_walk", "hnsw_clusters", "discover_logical_edges", "materialize_logical_edges", "detect_temporal_patterns"])
|
|
3901
4455
|
.describe("Action (determines which fields are required)"),
|
|
3902
4456
|
start_entity: zod_1.z.string().optional().describe("Required for explore/shortest_path/semantic_walk (Start entity ID)"),
|
|
3903
4457
|
end_entity: zod_1.z.string().optional().describe("Optional for explore / required for shortest_path"),
|
|
3904
4458
|
max_hops: zod_1.z.number().optional().describe("Optional for explore"),
|
|
3905
4459
|
relation_types: zod_1.z.array(zod_1.z.string()).optional().describe("Optional for explore"),
|
|
3906
|
-
entity_id: zod_1.z.string().optional().describe("Required for infer_relations"),
|
|
4460
|
+
entity_id: zod_1.z.string().optional().describe("Required for infer_relations/discover_logical_edges/materialize_logical_edges/detect_temporal_patterns"),
|
|
3907
4461
|
from_id: zod_1.z.string().optional().describe("Required for get_relation_evolution"),
|
|
3908
4462
|
to_id: zod_1.z.string().optional().describe("Optional for get_relation_evolution"),
|
|
3909
4463
|
max_depth: zod_1.z.number().optional().describe("Optional for semantic_walk"),
|
|
@@ -3926,7 +4480,10 @@ Supported actions:
|
|
|
3926
4480
|
- 'infer_relations': Starts the inference engine for an entity. Params: { entity_id: string }.
|
|
3927
4481
|
- 'get_relation_evolution': Tracks the temporal evolution of relationships. Params: { from_id: string, to_id?: string }.
|
|
3928
4482
|
- 'semantic_walk': Performs a recursive "Graph Walk" that follows both explicit relationships and semantic similarity. Params: { start_entity: string, max_depth?: number, min_similarity?: number }.
|
|
3929
|
-
- 'hnsw_clusters': Analyzes clusters directly on the HNSW graph (Layer 0). Extremely fast as no vector calculations are needed
|
|
4483
|
+
- 'hnsw_clusters': Analyzes clusters directly on the HNSW graph (Layer 0). Extremely fast as no vector calculations are needed.
|
|
4484
|
+
- 'discover_logical_edges': Discovers implicit logical edges for an entity (same category, type, hierarchical, contextual, transitive). Params: { entity_id: string }.
|
|
4485
|
+
- 'materialize_logical_edges': Materializes discovered logical edges as actual relationships in the graph. Params: { entity_id: string }.
|
|
4486
|
+
- 'detect_temporal_patterns': Detects temporal patterns in entity observations (periodic, trending, seasonal). Params: { entity_id: string }.`,
|
|
3930
4487
|
parameters: AnalyzeGraphParameters,
|
|
3931
4488
|
execute: async (args) => {
|
|
3932
4489
|
await this.initPromise;
|
|
@@ -4181,6 +4738,98 @@ Supported actions:
|
|
|
4181
4738
|
return JSON.stringify({ error: error.message || "Error during HNSW Cluster Analysis" });
|
|
4182
4739
|
}
|
|
4183
4740
|
}
|
|
4741
|
+
if (input.action === "discover_logical_edges") {
|
|
4742
|
+
try {
|
|
4743
|
+
if (!input.entity_id) {
|
|
4744
|
+
return JSON.stringify({ error: "entity_id is required for discover_logical_edges" });
|
|
4745
|
+
}
|
|
4746
|
+
const edges = await this.getLogicalEdgesService().discoverLogicalEdges(input.entity_id);
|
|
4747
|
+
return JSON.stringify({
|
|
4748
|
+
entity_id: input.entity_id,
|
|
4749
|
+
edge_count: edges.length,
|
|
4750
|
+
edges
|
|
4751
|
+
});
|
|
4752
|
+
}
|
|
4753
|
+
catch (error) {
|
|
4754
|
+
return JSON.stringify({ error: error.message || "Error discovering logical edges" });
|
|
4755
|
+
}
|
|
4756
|
+
}
|
|
4757
|
+
if (input.action === "materialize_logical_edges") {
|
|
4758
|
+
try {
|
|
4759
|
+
if (!input.entity_id) {
|
|
4760
|
+
return JSON.stringify({ error: "entity_id is required for materialize_logical_edges" });
|
|
4761
|
+
}
|
|
4762
|
+
const count = await this.getLogicalEdgesService().materializeLogicalEdges(input.entity_id);
|
|
4763
|
+
return JSON.stringify({
|
|
4764
|
+
entity_id: input.entity_id,
|
|
4765
|
+
materialized_count: count,
|
|
4766
|
+
status: `${count} logical edges materialized as relationships`
|
|
4767
|
+
});
|
|
4768
|
+
}
|
|
4769
|
+
catch (error) {
|
|
4770
|
+
return JSON.stringify({ error: error.message || "Error materializing logical edges" });
|
|
4771
|
+
}
|
|
4772
|
+
}
|
|
4773
|
+
if (input.action === "detect_temporal_patterns") {
|
|
4774
|
+
try {
|
|
4775
|
+
if (!input.entity_id) {
|
|
4776
|
+
return JSON.stringify({ error: "entity_id is required for detect_temporal_patterns" });
|
|
4777
|
+
}
|
|
4778
|
+
// Check if entity exists
|
|
4779
|
+
const entityRes = await this.db.run('?[name] := *entity{id: $id, name, @ "NOW"}', { id: input.entity_id });
|
|
4780
|
+
if (entityRes.rows.length === 0) {
|
|
4781
|
+
return JSON.stringify({ error: `Entity with ID '${input.entity_id}' not found` });
|
|
4782
|
+
}
|
|
4783
|
+
// Get observations for the entity
|
|
4784
|
+
const obsRes = await this.db.run(`
|
|
4785
|
+
?[id, text, created_at] :=
|
|
4786
|
+
*observation{id, entity_id, text, created_at, @ "NOW"},
|
|
4787
|
+
entity_id = $entity_id
|
|
4788
|
+
`, { entity_id: input.entity_id });
|
|
4789
|
+
if (obsRes.rows.length === 0) {
|
|
4790
|
+
return JSON.stringify({
|
|
4791
|
+
entity_id: input.entity_id,
|
|
4792
|
+
patterns: [],
|
|
4793
|
+
message: "No observations found for temporal pattern detection"
|
|
4794
|
+
});
|
|
4795
|
+
}
|
|
4796
|
+
// Simple temporal pattern detection
|
|
4797
|
+
const observations = obsRes.rows.map((r) => ({
|
|
4798
|
+
id: r[0],
|
|
4799
|
+
text: r[1],
|
|
4800
|
+
timestamp: r[2][0] / 1000 // Convert microseconds to milliseconds
|
|
4801
|
+
}));
|
|
4802
|
+
// Sort by timestamp
|
|
4803
|
+
observations.sort((a, b) => a.timestamp - b.timestamp);
|
|
4804
|
+
const patterns = [];
|
|
4805
|
+
// Detect trending (increasing frequency over time)
|
|
4806
|
+
if (observations.length >= 3) {
|
|
4807
|
+
const timeSpan = observations[observations.length - 1].timestamp - observations[0].timestamp;
|
|
4808
|
+
const avgInterval = timeSpan / (observations.length - 1);
|
|
4809
|
+
if (avgInterval < 7 * 24 * 60 * 60 * 1000) { // Less than a week
|
|
4810
|
+
patterns.push({
|
|
4811
|
+
type: "trending",
|
|
4812
|
+
confidence: 0.8,
|
|
4813
|
+
description: "High frequency of observations detected",
|
|
4814
|
+
observation_count: observations.length,
|
|
4815
|
+
time_span_days: (timeSpan / (24 * 60 * 60 * 1000)).toFixed(1)
|
|
4816
|
+
});
|
|
4817
|
+
}
|
|
4818
|
+
}
|
|
4819
|
+
return JSON.stringify({
|
|
4820
|
+
entity_id: input.entity_id,
|
|
4821
|
+
observation_count: observations.length,
|
|
4822
|
+
patterns,
|
|
4823
|
+
time_range: {
|
|
4824
|
+
start: new Date(observations[0].timestamp).toISOString(),
|
|
4825
|
+
end: new Date(observations[observations.length - 1].timestamp).toISOString()
|
|
4826
|
+
}
|
|
4827
|
+
});
|
|
4828
|
+
}
|
|
4829
|
+
catch (error) {
|
|
4830
|
+
return JSON.stringify({ error: error.message || "Error detecting temporal patterns" });
|
|
4831
|
+
}
|
|
4832
|
+
}
|
|
4184
4833
|
return JSON.stringify({ error: "Unknown action" });
|
|
4185
4834
|
},
|
|
4186
4835
|
});
|
|
@@ -4248,10 +4897,19 @@ Supported actions:
|
|
|
4248
4897
|
entity_id: zod_1.z.string().optional().describe("Entity ID to compact"),
|
|
4249
4898
|
model: zod_1.z.string().optional().default("demyagent-4b-i1:Q6_K"),
|
|
4250
4899
|
}),
|
|
4900
|
+
zod_1.z.object({
|
|
4901
|
+
action: zod_1.z.literal("compress_memory_levels"),
|
|
4902
|
+
entity_id: zod_1.z.string().describe("Entity ID to compress memory levels for"),
|
|
4903
|
+
level: zod_1.z.number().min(0).max(3).describe("Memory level to compress (0-3: L0_RAW, L1_SESSION, L2_WEEKLY, L3_MONTHLY)"),
|
|
4904
|
+
}),
|
|
4905
|
+
zod_1.z.object({
|
|
4906
|
+
action: zod_1.z.literal("analyze_memory_distribution"),
|
|
4907
|
+
entity_id: zod_1.z.string().describe("Entity ID to analyze memory distribution for"),
|
|
4908
|
+
}),
|
|
4251
4909
|
]);
|
|
4252
4910
|
const ManageSystemParameters = zod_1.z.object({
|
|
4253
4911
|
action: zod_1.z
|
|
4254
|
-
.enum(["health", "metrics", "export_memory", "import_memory", "snapshot_create", "snapshot_list", "snapshot_diff", "cleanup", "defrag", "reflect", "clear_memory", "summarize_communities", "compact"])
|
|
4912
|
+
.enum(["health", "metrics", "export_memory", "import_memory", "snapshot_create", "snapshot_list", "snapshot_diff", "cleanup", "defrag", "reflect", "clear_memory", "summarize_communities", "compact", "compress_memory_levels", "analyze_memory_distribution"])
|
|
4255
4913
|
.describe("Action (determines which fields are required)"),
|
|
4256
4914
|
format: zod_1.z.enum(["json", "markdown", "obsidian"]).optional().describe("Export format (for export_memory)"),
|
|
4257
4915
|
includeMetadata: zod_1.z.boolean().optional().describe("Include metadata (for export_memory)"),
|
|
@@ -4273,9 +4931,10 @@ Supported actions:
|
|
|
4273
4931
|
similarity_threshold: zod_1.z.number().optional().describe("Optional for defrag (0.8-1.0, default 0.95)"),
|
|
4274
4932
|
min_island_size: zod_1.z.number().optional().describe("Optional for defrag (1-10, default 3)"),
|
|
4275
4933
|
model: zod_1.z.string().optional().describe("Optional for cleanup/reflect/summarize_communities"),
|
|
4276
|
-
entity_id: zod_1.z.string().optional().describe("Optional for reflect"),
|
|
4934
|
+
entity_id: zod_1.z.string().optional().describe("Optional for reflect, required for compress_memory_levels/analyze_memory_distribution"),
|
|
4277
4935
|
min_community_size: zod_1.z.number().optional().describe("Optional for summarize_communities"),
|
|
4278
4936
|
mode: zod_1.z.enum(["summary", "discovery"]).optional().describe("Optional for reflect"),
|
|
4937
|
+
level: zod_1.z.number().optional().describe("Required for compress_memory_levels (0-3: L0_RAW, L1_SESSION, L2_WEEKLY, L3_MONTHLY)"),
|
|
4279
4938
|
});
|
|
4280
4939
|
this.mcp.addTool({
|
|
4281
4940
|
name: "manage_system",
|
|
@@ -4303,7 +4962,9 @@ Supported actions:
|
|
|
4303
4962
|
* With confirm=true: Executes defragmentation and returns statistics.
|
|
4304
4963
|
- 'reflect': Reflection service. Analyzes memory for contradictions and insights. Params: { entity_id?: string, model?: string }.
|
|
4305
4964
|
- 'clear_memory': Resets the entire database. Params: { confirm: boolean (must be true) }.
|
|
4306
|
-
- 'summarize_communities': Hierarchical GraphRAG. Generates summaries for entity clusters. Params: { model?: string, min_community_size?: number }
|
|
4965
|
+
- 'summarize_communities': Hierarchical GraphRAG. Generates summaries for entity clusters. Params: { model?: string, min_community_size?: number }.
|
|
4966
|
+
- 'compress_memory_levels': Hierarchical memory compression. Compresses observations at a specific memory level using LLM summarization. Params: { entity_id: string, level: number (0-3) }.
|
|
4967
|
+
- 'analyze_memory_distribution': Analyzes memory distribution across hierarchical levels. Params: { entity_id: string }.`,
|
|
4307
4968
|
parameters: ManageSystemParameters,
|
|
4308
4969
|
execute: async (args) => {
|
|
4309
4970
|
await this.initPromise;
|
|
@@ -4573,6 +5234,62 @@ Supported actions:
|
|
|
4573
5234
|
return JSON.stringify({ error: error.message || "Error during compaction" });
|
|
4574
5235
|
}
|
|
4575
5236
|
}
|
|
5237
|
+
if (input.action === "compress_memory_levels") {
|
|
5238
|
+
try {
|
|
5239
|
+
if (!input.entity_id) {
|
|
5240
|
+
return JSON.stringify({ error: "entity_id is required for compress_memory_levels" });
|
|
5241
|
+
}
|
|
5242
|
+
if (input.level === undefined || input.level === null) {
|
|
5243
|
+
return JSON.stringify({ error: "level is required (0-3: L0_RAW, L1_SESSION, L2_WEEKLY, L3_MONTHLY)" });
|
|
5244
|
+
}
|
|
5245
|
+
if (input.level < 0 || input.level > 3) {
|
|
5246
|
+
return JSON.stringify({ error: "level must be between 0 and 3" });
|
|
5247
|
+
}
|
|
5248
|
+
const result = await this.getHierarchicalMemoryService().compressMemoryLevel(input.entity_id, input.level);
|
|
5249
|
+
if (!result) {
|
|
5250
|
+
return JSON.stringify({
|
|
5251
|
+
entity_id: input.entity_id,
|
|
5252
|
+
level: input.level,
|
|
5253
|
+
status: "no_compression_needed",
|
|
5254
|
+
message: "Not enough observations for compression at this level"
|
|
5255
|
+
});
|
|
5256
|
+
}
|
|
5257
|
+
return JSON.stringify({
|
|
5258
|
+
entity_id: input.entity_id,
|
|
5259
|
+
level: result.level,
|
|
5260
|
+
compressed_observations: result.compressed_observations,
|
|
5261
|
+
summary_id: result.summary_id,
|
|
5262
|
+
preserved_count: result.preserved_observations.length,
|
|
5263
|
+
deleted_count: result.deleted_observations.length,
|
|
5264
|
+
status: "compression_completed"
|
|
5265
|
+
});
|
|
5266
|
+
}
|
|
5267
|
+
catch (error) {
|
|
5268
|
+
return JSON.stringify({ error: error.message || "Error compressing memory levels" });
|
|
5269
|
+
}
|
|
5270
|
+
}
|
|
5271
|
+
if (input.action === "analyze_memory_distribution") {
|
|
5272
|
+
try {
|
|
5273
|
+
if (!input.entity_id) {
|
|
5274
|
+
return JSON.stringify({ error: "entity_id is required for analyze_memory_distribution" });
|
|
5275
|
+
}
|
|
5276
|
+
const stats = await this.getHierarchicalMemoryService().getMemoryStats(input.entity_id);
|
|
5277
|
+
return JSON.stringify({
|
|
5278
|
+
entity_id: input.entity_id,
|
|
5279
|
+
total_observations: stats.total_observations,
|
|
5280
|
+
distribution: {
|
|
5281
|
+
L0_RAW: stats.by_level[0] || 0,
|
|
5282
|
+
L1_SESSION: stats.by_level[1] || 0,
|
|
5283
|
+
L2_WEEKLY: stats.by_level[2] || 0,
|
|
5284
|
+
L3_MONTHLY: stats.by_level[3] || 0
|
|
5285
|
+
},
|
|
5286
|
+
avg_importance: stats.avg_importance
|
|
5287
|
+
});
|
|
5288
|
+
}
|
|
5289
|
+
catch (error) {
|
|
5290
|
+
return JSON.stringify({ error: error.message || "Error analyzing memory distribution" });
|
|
5291
|
+
}
|
|
5292
|
+
}
|
|
4576
5293
|
return JSON.stringify({ error: "Unknown action" });
|
|
4577
5294
|
},
|
|
4578
5295
|
});
|