@prmichaelsen/remember-mcp 2.8.0 → 3.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/AGENT.md +1 -1
- package/CHANGELOG.md +130 -0
- package/README.md +95 -1
- package/agent/commands/acp.command-create.md +0 -1
- package/agent/commands/acp.design-create.md +0 -1
- package/agent/commands/acp.init.md +0 -1
- package/agent/commands/acp.package-create.md +0 -1
- package/agent/commands/acp.package-info.md +0 -1
- package/agent/commands/acp.package-install.md +0 -1
- package/agent/commands/acp.package-list.md +0 -1
- package/agent/commands/acp.package-publish.md +0 -1
- package/agent/commands/acp.package-remove.md +0 -1
- package/agent/commands/acp.package-search.md +0 -1
- package/agent/commands/acp.package-update.md +0 -1
- package/agent/commands/acp.package-validate.md +0 -1
- package/agent/commands/acp.pattern-create.md +0 -1
- package/agent/commands/acp.plan.md +0 -1
- package/agent/commands/acp.proceed.md +0 -1
- package/agent/commands/acp.project-create.md +0 -1
- package/agent/commands/acp.project-list.md +0 -1
- package/agent/commands/acp.project-set.md +0 -1
- package/agent/commands/acp.report.md +0 -1
- package/agent/commands/acp.resume.md +0 -1
- package/agent/commands/acp.status.md +0 -1
- package/agent/commands/acp.sync.md +0 -1
- package/agent/commands/acp.task-create.md +0 -1
- package/agent/commands/acp.update.md +0 -1
- package/agent/commands/acp.validate.md +0 -1
- package/agent/commands/acp.version-check-for-updates.md +0 -1
- package/agent/commands/acp.version-check.md +0 -1
- package/agent/commands/acp.version-update.md +0 -1
- package/agent/commands/command.template.md +0 -5
- package/agent/commands/git.commit.md +0 -1
- package/agent/commands/git.init.md +0 -1
- package/agent/design/soft-delete-system.md +291 -0
- package/agent/milestones/milestone-13-soft-delete-system.md +306 -0
- package/agent/package.template.yaml +0 -17
- package/agent/progress.yaml +136 -2
- package/agent/scripts/acp.install.sh +4 -84
- package/agent/scripts/acp.package-install.sh +33 -112
- package/agent/scripts/acp.package-validate.sh +0 -99
- package/agent/tasks/task-70-add-soft-delete-schema-fields.md +165 -0
- package/agent/tasks/task-71-implement-delete-confirmation-flow.md +257 -0
- package/agent/tasks/task-72-add-deleted-filter-to-search-tools.md +18 -0
- package/agent/tasks/task-73-update-relationship-handling.md +18 -0
- package/agent/tasks/task-74-add-unit-tests-soft-delete.md +18 -0
- package/agent/tasks/task-75-update-documentation-changelog.md +26 -0
- package/dist/server-factory.js +677 -501
- package/dist/server.js +677 -501
- package/dist/tools/delete-memory.d.ts +5 -30
- package/dist/tools/find-similar.d.ts +8 -1
- package/dist/tools/query-memory.d.ts +8 -1
- package/dist/tools/search-memory.d.ts +6 -0
- package/dist/tools/search-relationship.d.ts +8 -1
- package/dist/types/memory.d.ts +8 -0
- package/dist/types/space-memory.d.ts +3 -0
- package/dist/utils/weaviate-filters.d.ts +19 -0
- package/dist/weaviate/client.d.ts +1 -1
- package/package.json +1 -1
- package/src/tools/confirm.ts +65 -1
- package/src/tools/create-relationship.ts +14 -1
- package/src/tools/delete-memory.ts +91 -63
- package/src/tools/find-similar.ts +30 -5
- package/src/tools/query-memory.ts +18 -5
- package/src/tools/search-memory.ts +18 -5
- package/src/tools/search-relationship.ts +19 -5
- package/src/tools/update-memory.ts +8 -0
- package/src/types/memory.ts +11 -0
- package/src/types/space-memory.ts +5 -0
- package/src/utils/weaviate-filters.ts +28 -1
- package/src/weaviate/client.ts +5 -0
- package/src/weaviate/schema.ts +17 -0
- package/src/weaviate/space-schema.spec.ts +5 -2
- package/src/weaviate/space-schema.ts +17 -5
|
@@ -1,47 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* remember_delete_memory tool
|
|
3
|
-
*
|
|
3
|
+
* Request to delete a memory (requires confirmation)
|
|
4
4
|
*/
|
|
5
|
+
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
5
6
|
/**
|
|
6
7
|
* Tool definition for remember_delete_memory
|
|
7
8
|
*/
|
|
8
|
-
export declare const deleteMemoryTool:
|
|
9
|
-
name: string;
|
|
10
|
-
description: string;
|
|
11
|
-
inputSchema: {
|
|
12
|
-
type: string;
|
|
13
|
-
properties: {
|
|
14
|
-
memory_id: {
|
|
15
|
-
type: string;
|
|
16
|
-
description: string;
|
|
17
|
-
};
|
|
18
|
-
delete_relationships: {
|
|
19
|
-
type: string;
|
|
20
|
-
description: string;
|
|
21
|
-
default: boolean;
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
required: string[];
|
|
25
|
-
};
|
|
26
|
-
};
|
|
9
|
+
export declare const deleteMemoryTool: Tool;
|
|
27
10
|
/**
|
|
28
11
|
* Delete memory arguments
|
|
29
12
|
*/
|
|
30
13
|
export interface DeleteMemoryArgs {
|
|
31
14
|
memory_id: string;
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Delete memory result
|
|
36
|
-
*/
|
|
37
|
-
export interface DeleteMemoryResult {
|
|
38
|
-
memory_id: string;
|
|
39
|
-
deleted: boolean;
|
|
40
|
-
relationships_deleted?: number;
|
|
41
|
-
message: string;
|
|
15
|
+
reason?: string;
|
|
42
16
|
}
|
|
43
17
|
/**
|
|
44
18
|
* Handle remember_delete_memory tool
|
|
19
|
+
* Creates confirmation token and returns preview
|
|
45
20
|
*/
|
|
46
21
|
export declare function handleDeleteMemory(args: DeleteMemoryArgs, userId: string): Promise<string>;
|
|
47
22
|
//# sourceMappingURL=delete-memory.d.ts.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* remember_find_similar tool
|
|
3
3
|
* Find similar memories using vector similarity search
|
|
4
4
|
*/
|
|
5
|
-
import type { Memory } from '../types/memory.js';
|
|
5
|
+
import type { Memory, DeletedFilter } from '../types/memory.js';
|
|
6
6
|
/**
|
|
7
7
|
* Tool definition for remember_find_similar
|
|
8
8
|
*/
|
|
@@ -39,6 +39,12 @@ export declare const findSimilarTool: {
|
|
|
39
39
|
description: string;
|
|
40
40
|
default: boolean;
|
|
41
41
|
};
|
|
42
|
+
deleted_filter: {
|
|
43
|
+
type: string;
|
|
44
|
+
enum: string[];
|
|
45
|
+
default: string;
|
|
46
|
+
description: string;
|
|
47
|
+
};
|
|
42
48
|
};
|
|
43
49
|
};
|
|
44
50
|
};
|
|
@@ -51,6 +57,7 @@ export interface FindSimilarArgs {
|
|
|
51
57
|
limit?: number;
|
|
52
58
|
min_similarity?: number;
|
|
53
59
|
include_relationships?: boolean;
|
|
60
|
+
deleted_filter?: DeletedFilter;
|
|
54
61
|
}
|
|
55
62
|
/**
|
|
56
63
|
* Similar memory result
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* remember_query_memory tool
|
|
3
3
|
* RAG (Retrieval-Augmented Generation) queries with natural language
|
|
4
4
|
*/
|
|
5
|
-
import type { Memory, SearchFilters } from '../types/memory.js';
|
|
5
|
+
import type { Memory, SearchFilters, DeletedFilter } from '../types/memory.js';
|
|
6
6
|
/**
|
|
7
7
|
* Tool definition for remember_query_memory
|
|
8
8
|
*/
|
|
@@ -77,6 +77,12 @@ export declare const queryMemoryTool: {
|
|
|
77
77
|
enum: string[];
|
|
78
78
|
default: string;
|
|
79
79
|
};
|
|
80
|
+
deleted_filter: {
|
|
81
|
+
type: string;
|
|
82
|
+
enum: string[];
|
|
83
|
+
default: string;
|
|
84
|
+
description: string;
|
|
85
|
+
};
|
|
80
86
|
};
|
|
81
87
|
required: string[];
|
|
82
88
|
};
|
|
@@ -91,6 +97,7 @@ export interface QueryMemoryArgs {
|
|
|
91
97
|
filters?: SearchFilters;
|
|
92
98
|
include_context?: boolean;
|
|
93
99
|
format?: 'detailed' | 'compact';
|
|
100
|
+
deleted_filter?: DeletedFilter;
|
|
94
101
|
}
|
|
95
102
|
/**
|
|
96
103
|
* Memory with relevance score
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* remember_search_relationship tool
|
|
3
3
|
* Search relationships by observation text or type
|
|
4
4
|
*/
|
|
5
|
-
import type { Relationship } from '../types/memory.js';
|
|
5
|
+
import type { Relationship, DeletedFilter } from '../types/memory.js';
|
|
6
6
|
/**
|
|
7
7
|
* Tool definition for remember_search_relationship
|
|
8
8
|
*/
|
|
@@ -53,6 +53,12 @@ export declare const searchRelationshipTool: {
|
|
|
53
53
|
description: string;
|
|
54
54
|
minimum: number;
|
|
55
55
|
};
|
|
56
|
+
deleted_filter: {
|
|
57
|
+
type: string;
|
|
58
|
+
enum: string[];
|
|
59
|
+
default: string;
|
|
60
|
+
description: string;
|
|
61
|
+
};
|
|
56
62
|
};
|
|
57
63
|
required: string[];
|
|
58
64
|
};
|
|
@@ -68,6 +74,7 @@ export interface SearchRelationshipArgs {
|
|
|
68
74
|
tags?: string[];
|
|
69
75
|
limit?: number;
|
|
70
76
|
offset?: number;
|
|
77
|
+
deleted_filter?: DeletedFilter;
|
|
71
78
|
}
|
|
72
79
|
/**
|
|
73
80
|
* Search relationship result
|
package/dist/types/memory.d.ts
CHANGED
|
@@ -114,6 +114,9 @@ export interface Memory {
|
|
|
114
114
|
parent_id?: string | null;
|
|
115
115
|
thread_root_id?: string | null;
|
|
116
116
|
moderation_flags?: string[];
|
|
117
|
+
deleted_at?: Date | null;
|
|
118
|
+
deleted_by?: string;
|
|
119
|
+
deletion_reason?: string;
|
|
117
120
|
}
|
|
118
121
|
/**
|
|
119
122
|
* Relationship interface
|
|
@@ -162,6 +165,10 @@ export interface SearchFilters {
|
|
|
162
165
|
location_radius_meters?: number;
|
|
163
166
|
has_relationships?: boolean;
|
|
164
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Deleted filter type
|
|
170
|
+
*/
|
|
171
|
+
export type DeletedFilter = 'exclude' | 'include' | 'only';
|
|
165
172
|
/**
|
|
166
173
|
* Search options
|
|
167
174
|
*/
|
|
@@ -170,6 +177,7 @@ export interface SearchOptions {
|
|
|
170
177
|
alpha?: number;
|
|
171
178
|
filters?: SearchFilters;
|
|
172
179
|
include_relationships?: boolean;
|
|
180
|
+
deleted_filter?: DeletedFilter;
|
|
173
181
|
limit?: number;
|
|
174
182
|
offset?: number;
|
|
175
183
|
}
|
|
@@ -47,6 +47,9 @@ export interface SpaceMemory extends Omit<Memory, 'user_id' | 'doc_type'> {
|
|
|
47
47
|
* Always 'space_memory' for space memories
|
|
48
48
|
*/
|
|
49
49
|
doc_type: 'space_memory';
|
|
50
|
+
deleted_at?: Date | null;
|
|
51
|
+
deleted_by?: string;
|
|
52
|
+
deletion_reason?: string;
|
|
50
53
|
}
|
|
51
54
|
/**
|
|
52
55
|
* Search options for space memories
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
* Replaces old v2 filter format (path/operator/valueText) with v3 collection.filter.byProperty()
|
|
6
6
|
*/
|
|
7
7
|
import type { SearchFilters } from '../types/memory.js';
|
|
8
|
+
/**
|
|
9
|
+
* Deleted filter options
|
|
10
|
+
*/
|
|
11
|
+
export type DeletedFilter = 'exclude' | 'include' | 'only';
|
|
8
12
|
/**
|
|
9
13
|
* Build filters for searching both memories and relationships
|
|
10
14
|
* Uses OR logic: (doc_type=memory AND memory_filters) OR (doc_type=relationship AND relationship_filters)
|
|
@@ -30,8 +34,23 @@ export declare function buildMemoryOnlyFilters(collection: any, filters?: Search
|
|
|
30
34
|
* @returns Combined filter or undefined if no filters
|
|
31
35
|
*/
|
|
32
36
|
export declare function buildRelationshipOnlyFilters(collection: any, filters?: SearchFilters): any;
|
|
37
|
+
/**
|
|
38
|
+
* Combine multiple filters with AND logic
|
|
39
|
+
*
|
|
40
|
+
* @param filters - Array of filter objects
|
|
41
|
+
* @returns Combined filter or undefined
|
|
42
|
+
*/
|
|
43
|
+
export declare function combineFiltersWithAnd(filters: any[]): any;
|
|
33
44
|
/**
|
|
34
45
|
* Helper to check if a filter result is empty
|
|
35
46
|
*/
|
|
36
47
|
export declare function hasFilters(filter: any): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Build filter for deleted_at field based on deleted_filter parameter
|
|
50
|
+
*
|
|
51
|
+
* @param collection - Weaviate collection instance
|
|
52
|
+
* @param deletedFilter - Filter mode: 'exclude' (default), 'include', or 'only'
|
|
53
|
+
* @returns Filter for deleted_at field, or null if no filter needed
|
|
54
|
+
*/
|
|
55
|
+
export declare function buildDeletedFilter(collection: any, deletedFilter?: DeletedFilter): any | null;
|
|
37
56
|
//# sourceMappingURL=weaviate-filters.d.ts.map
|
|
@@ -41,7 +41,7 @@ export declare function getAuditCollectionName(userId: string): string;
|
|
|
41
41
|
* List of all memory properties to fetch
|
|
42
42
|
* Matches the actual Weaviate schema properties exactly
|
|
43
43
|
*/
|
|
44
|
-
export declare const ALL_MEMORY_PROPERTIES: readonly ["user_id", "doc_type", "content", "title", "summary", "type", "weight", "base_weight", "trust", "confidence", "computed_weight", "location_gps_lat", "location_gps_lng", "location_address", "location_city", "location_country", "location_source", "locale_language", "locale_timezone", "context_conversation_id", "context_summary", "context_timestamp", "relationships", "access_count", "last_accessed_at", "tags", "references", "created_at", "updated_at", "version", "template_id", "memory_ids", "relationship_type", "observation", "strength", "parent_id", "thread_root_id", "moderation_flags", "spaces", "space_id", "author_id", "ghost_id", "attribution", "published_at", "discovery_count", "space_memory_id"];
|
|
44
|
+
export declare const ALL_MEMORY_PROPERTIES: readonly ["user_id", "doc_type", "content", "title", "summary", "type", "weight", "base_weight", "trust", "confidence", "computed_weight", "location_gps_lat", "location_gps_lng", "location_address", "location_city", "location_country", "location_source", "locale_language", "locale_timezone", "context_conversation_id", "context_summary", "context_timestamp", "relationships", "access_count", "last_accessed_at", "tags", "references", "created_at", "updated_at", "version", "template_id", "memory_ids", "relationship_type", "observation", "strength", "parent_id", "thread_root_id", "moderation_flags", "spaces", "space_id", "author_id", "ghost_id", "attribution", "published_at", "discovery_count", "space_memory_id", "deleted_at", "deleted_by", "deletion_reason"];
|
|
45
45
|
/**
|
|
46
46
|
* Fetch a memory object by ID with all properties
|
|
47
47
|
*
|
package/package.json
CHANGED
package/src/tools/confirm.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
9
9
|
import { confirmationTokenService, type ConfirmationRequest } from '../services/confirmation-token.service.js';
|
|
10
|
-
import { getWeaviateClient, getMemoryCollectionName, fetchMemoryWithAllProperties } from '../weaviate/client.js';
|
|
10
|
+
import { getWeaviateClient, getMemoryCollectionName, fetchMemoryWithAllProperties, sanitizeUserId } from '../weaviate/client.js';
|
|
11
11
|
import { ensurePublicCollection } from '../weaviate/space-schema.js';
|
|
12
12
|
import { handleToolError } from '../utils/error-handler.js';
|
|
13
13
|
import { logger } from '../utils/logger.js';
|
|
@@ -120,6 +120,11 @@ export async function handleConfirm(
|
|
|
120
120
|
return await executePublishMemory(request, userId);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
// Handle delete_memory action
|
|
124
|
+
if (request.action === 'delete_memory') {
|
|
125
|
+
return await executeDeleteMemory(request, userId);
|
|
126
|
+
}
|
|
127
|
+
|
|
123
128
|
// Add other action types here as needed
|
|
124
129
|
// if (request.action === 'retract_memory') {
|
|
125
130
|
// return await executeRetractMemory(request, userId);
|
|
@@ -380,3 +385,62 @@ async function executePublishMemory(
|
|
|
380
385
|
});
|
|
381
386
|
}
|
|
382
387
|
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Execute delete memory action
|
|
391
|
+
*/
|
|
392
|
+
async function executeDeleteMemory(
|
|
393
|
+
request: ConfirmationRequest & { request_id: string },
|
|
394
|
+
userId: string
|
|
395
|
+
): Promise<string> {
|
|
396
|
+
try {
|
|
397
|
+
logger.info('Executing delete memory action', {
|
|
398
|
+
function: 'executeDeleteMemory',
|
|
399
|
+
userId,
|
|
400
|
+
memoryId: request.payload.memory_id,
|
|
401
|
+
hasReason: !!request.payload.reason,
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
const { memory_id, reason } = request.payload;
|
|
405
|
+
|
|
406
|
+
// Soft delete the memory
|
|
407
|
+
const client = getWeaviateClient();
|
|
408
|
+
const collectionName = `Memory_${sanitizeUserId(userId)}`;
|
|
409
|
+
const collection = client.collections.get(collectionName);
|
|
410
|
+
|
|
411
|
+
await collection.data.update({
|
|
412
|
+
id: memory_id,
|
|
413
|
+
properties: {
|
|
414
|
+
deleted_at: new Date().toISOString(),
|
|
415
|
+
deleted_by: userId,
|
|
416
|
+
deletion_reason: reason || null,
|
|
417
|
+
},
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
logger.info('Memory soft-deleted successfully', {
|
|
421
|
+
function: 'executeDeleteMemory',
|
|
422
|
+
userId,
|
|
423
|
+
memoryId: memory_id,
|
|
424
|
+
deletedAt: new Date().toISOString(),
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
return JSON.stringify(
|
|
428
|
+
{
|
|
429
|
+
success: true,
|
|
430
|
+
memory_id,
|
|
431
|
+
message: 'Memory deleted successfully',
|
|
432
|
+
},
|
|
433
|
+
null,
|
|
434
|
+
2
|
|
435
|
+
);
|
|
436
|
+
} catch (error) {
|
|
437
|
+
logger.error('Failed to execute delete memory', {
|
|
438
|
+
function: 'executeDeleteMemory',
|
|
439
|
+
userId,
|
|
440
|
+
memoryId: request.payload.memory_id,
|
|
441
|
+
error: error instanceof Error ? error.message : String(error),
|
|
442
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
443
|
+
});
|
|
444
|
+
throw error;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
@@ -117,7 +117,7 @@ export async function handleCreateRelationship(
|
|
|
117
117
|
args.memory_ids.map(async (memoryId) => {
|
|
118
118
|
try {
|
|
119
119
|
const memory = await collection.query.fetchObjectById(memoryId, {
|
|
120
|
-
returnProperties: ['user_id', 'doc_type', 'relationships'],
|
|
120
|
+
returnProperties: ['user_id', 'doc_type', 'relationships', 'deleted_at'],
|
|
121
121
|
});
|
|
122
122
|
|
|
123
123
|
if (!memory) {
|
|
@@ -143,6 +143,19 @@ export async function handleCreateRelationship(
|
|
|
143
143
|
return { memoryId, error: 'Cannot create relationship with non-memory document' };
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
// Check if memory is deleted
|
|
147
|
+
if (memory.properties.deleted_at) {
|
|
148
|
+
const deletedAt = typeof memory.properties.deleted_at === 'string'
|
|
149
|
+
? memory.properties.deleted_at
|
|
150
|
+
: new Date(memory.properties.deleted_at as any).toISOString();
|
|
151
|
+
logger.warn('Attempt to create relationship with deleted memory', {
|
|
152
|
+
userId,
|
|
153
|
+
memoryId,
|
|
154
|
+
deletedAt
|
|
155
|
+
});
|
|
156
|
+
return { memoryId, error: `Memory is deleted (deleted on ${deletedAt})` };
|
|
157
|
+
}
|
|
158
|
+
|
|
146
159
|
return {
|
|
147
160
|
memoryId,
|
|
148
161
|
memory,
|
|
@@ -1,26 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* remember_delete_memory tool
|
|
3
|
-
*
|
|
3
|
+
* Request to delete a memory (requires confirmation)
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
7
|
+
import { Filters } from 'weaviate-client';
|
|
8
|
+
import { getWeaviateClient, sanitizeUserId, fetchMemoryWithAllProperties } from '../weaviate/client.js';
|
|
9
|
+
import { confirmationTokenService } from '../services/confirmation-token.service.js';
|
|
7
10
|
import { logger } from '../utils/logger.js';
|
|
8
11
|
import { handleToolError } from '../utils/error-handler.js';
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* Tool definition for remember_delete_memory
|
|
12
15
|
*/
|
|
13
|
-
export const deleteMemoryTool = {
|
|
16
|
+
export const deleteMemoryTool: Tool = {
|
|
14
17
|
name: 'remember_delete_memory',
|
|
15
|
-
description: `
|
|
18
|
+
description: `Request to delete a memory. Requires confirmation via remember_confirm.
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
⚠️ **IMPORTANT**: This is a two-step process:
|
|
21
|
+
1. Call remember_delete_memory to request deletion (returns token)
|
|
22
|
+
2. User must confirm via remember_confirm with the token
|
|
23
|
+
|
|
24
|
+
The memory will be soft-deleted (marked as deleted but not removed from database).
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
- "Delete that old camping note"
|
|
28
|
+
- "Remove the recipe I saved yesterday"
|
|
29
|
+
`,
|
|
24
30
|
inputSchema: {
|
|
25
31
|
type: 'object',
|
|
26
32
|
properties: {
|
|
@@ -28,10 +34,9 @@ export const deleteMemoryTool = {
|
|
|
28
34
|
type: 'string',
|
|
29
35
|
description: 'ID of the memory to delete',
|
|
30
36
|
},
|
|
31
|
-
|
|
32
|
-
type: '
|
|
33
|
-
description: '
|
|
34
|
-
default: false,
|
|
37
|
+
reason: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
description: 'Optional reason for deletion',
|
|
35
40
|
},
|
|
36
41
|
},
|
|
37
42
|
required: ['memory_id'],
|
|
@@ -43,43 +48,39 @@ export const deleteMemoryTool = {
|
|
|
43
48
|
*/
|
|
44
49
|
export interface DeleteMemoryArgs {
|
|
45
50
|
memory_id: string;
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Delete memory result
|
|
51
|
-
*/
|
|
52
|
-
export interface DeleteMemoryResult {
|
|
53
|
-
memory_id: string;
|
|
54
|
-
deleted: boolean;
|
|
55
|
-
relationships_deleted?: number;
|
|
56
|
-
message: string;
|
|
51
|
+
reason?: string;
|
|
57
52
|
}
|
|
58
53
|
|
|
59
54
|
/**
|
|
60
55
|
* Handle remember_delete_memory tool
|
|
56
|
+
* Creates confirmation token and returns preview
|
|
61
57
|
*/
|
|
62
58
|
export async function handleDeleteMemory(
|
|
63
59
|
args: DeleteMemoryArgs,
|
|
64
60
|
userId: string
|
|
65
61
|
): Promise<string> {
|
|
66
62
|
try {
|
|
67
|
-
logger.info('
|
|
63
|
+
logger.info('Requesting memory deletion', {
|
|
64
|
+
userId,
|
|
65
|
+
memoryId: args.memory_id,
|
|
66
|
+
hasReason: !!args.reason,
|
|
67
|
+
});
|
|
68
68
|
|
|
69
|
-
const
|
|
69
|
+
const { memory_id, reason } = args;
|
|
70
|
+
const client = getWeaviateClient();
|
|
71
|
+
const collectionName = `Memory_${sanitizeUserId(userId)}`;
|
|
72
|
+
const collection = client.collections.get(collectionName);
|
|
70
73
|
|
|
71
|
-
//
|
|
72
|
-
const memory = await collection
|
|
73
|
-
returnProperties: ['user_id', 'doc_type', 'relationships'],
|
|
74
|
-
});
|
|
74
|
+
// Fetch memory to verify ownership and get preview
|
|
75
|
+
const memory = await fetchMemoryWithAllProperties(collection, memory_id);
|
|
75
76
|
|
|
76
77
|
if (!memory) {
|
|
77
|
-
throw new Error(`Memory not found: ${
|
|
78
|
+
throw new Error(`Memory not found: ${memory_id}`);
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
// Verify ownership
|
|
81
82
|
if (memory.properties.user_id !== userId) {
|
|
82
|
-
throw new Error(
|
|
83
|
+
throw new Error(`Cannot delete memory: not owned by user ${userId}`);
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
// Verify it's a memory (not a relationship)
|
|
@@ -87,46 +88,73 @@ export async function handleDeleteMemory(
|
|
|
87
88
|
throw new Error('Cannot delete relationships using this tool. Use remember_delete_relationship instead.');
|
|
88
89
|
}
|
|
89
90
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (args.delete_relationships && memory.properties.relationships) {
|
|
94
|
-
const relationshipIds = memory.properties.relationships as string[];
|
|
95
|
-
|
|
96
|
-
for (const relId of relationshipIds) {
|
|
97
|
-
try {
|
|
98
|
-
await collection.data.deleteById(relId);
|
|
99
|
-
relationshipsDeleted++;
|
|
100
|
-
} catch (error) {
|
|
101
|
-
logger.warn(`Failed to delete relationship ${relId}:`, error);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
91
|
+
// Check if already deleted
|
|
92
|
+
if (memory.properties.deleted_at) {
|
|
93
|
+
throw new Error(`Memory ${memory_id} is already deleted`);
|
|
104
94
|
}
|
|
105
95
|
|
|
106
|
-
//
|
|
107
|
-
await collection.
|
|
96
|
+
// Find relationships that will be orphaned
|
|
97
|
+
const relationshipsResult = await collection.query.fetchObjects({
|
|
98
|
+
filters: Filters.and(
|
|
99
|
+
collection.filter.byProperty('doc_type').equal('relationship'),
|
|
100
|
+
collection.filter.byProperty('memory_ids').containsAny([memory_id])
|
|
101
|
+
),
|
|
102
|
+
limit: 100,
|
|
103
|
+
});
|
|
108
104
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
105
|
+
const orphanedRelationships = relationshipsResult.objects.map(r => r.uuid);
|
|
106
|
+
|
|
107
|
+
logger.info('Found relationships to orphan', {
|
|
108
|
+
userId,
|
|
109
|
+
memoryId: memory_id,
|
|
110
|
+
relationshipCount: orphanedRelationships.length,
|
|
113
111
|
});
|
|
114
112
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
113
|
+
// Create confirmation token
|
|
114
|
+
const { requestId, token } = await confirmationTokenService.createRequest(
|
|
115
|
+
userId,
|
|
116
|
+
'delete_memory',
|
|
117
|
+
{
|
|
118
|
+
memory_id,
|
|
119
|
+
reason: reason || null,
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
// Calculate expiry time (5 minutes from now)
|
|
124
|
+
const expiresAt = new Date(Date.now() + 5 * 60 * 1000);
|
|
125
|
+
|
|
126
|
+
logger.info('Delete confirmation token created', {
|
|
127
|
+
userId,
|
|
128
|
+
memoryId: memory_id,
|
|
129
|
+
requestId,
|
|
130
|
+
token,
|
|
131
|
+
expiresAt: expiresAt.toISOString(),
|
|
132
|
+
});
|
|
121
133
|
|
|
122
|
-
|
|
134
|
+
// Return token and preview
|
|
135
|
+
return JSON.stringify(
|
|
136
|
+
{
|
|
137
|
+
success: true,
|
|
138
|
+
token,
|
|
139
|
+
expires_at: expiresAt.toISOString(),
|
|
140
|
+
preview: {
|
|
141
|
+
memory_id,
|
|
142
|
+
content: memory.properties.content?.substring(0, 200) + (memory.properties.content?.length > 200 ? '...' : ''),
|
|
143
|
+
type: memory.properties.type,
|
|
144
|
+
relationships_count: orphanedRelationships.length,
|
|
145
|
+
will_orphan: orphanedRelationships,
|
|
146
|
+
},
|
|
147
|
+
message: `Deletion requested. Use remember_confirm with token to complete deletion. Token expires in 5 minutes.`,
|
|
148
|
+
},
|
|
149
|
+
null,
|
|
150
|
+
2
|
|
151
|
+
);
|
|
123
152
|
} catch (error) {
|
|
124
153
|
handleToolError(error, {
|
|
125
154
|
toolName: 'remember_delete_memory',
|
|
126
|
-
operation: 'delete memory',
|
|
127
155
|
userId,
|
|
156
|
+
operation: 'request delete',
|
|
128
157
|
memoryId: args.memory_id,
|
|
129
|
-
deleteRelationships: args.delete_relationships,
|
|
130
158
|
});
|
|
131
159
|
}
|
|
132
160
|
}
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
* Find similar memories using vector similarity search
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { Memory } from '../types/memory.js';
|
|
6
|
+
import type { Memory, DeletedFilter } from '../types/memory.js';
|
|
7
7
|
import { getMemoryCollection } from '../weaviate/schema.js';
|
|
8
8
|
import { logger } from '../utils/logger.js';
|
|
9
9
|
import { handleToolError } from '../utils/error-handler.js';
|
|
10
|
+
import { buildDeletedFilter } from '../utils/weaviate-filters.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Tool definition for remember_find_similar
|
|
@@ -54,6 +55,12 @@ export const findSimilarTool = {
|
|
|
54
55
|
description: 'Include relationships in results. Default: false',
|
|
55
56
|
default: false,
|
|
56
57
|
},
|
|
58
|
+
deleted_filter: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
enum: ['exclude', 'include', 'only'],
|
|
61
|
+
default: 'exclude',
|
|
62
|
+
description: 'Filter deleted memories: "exclude" (default, hide deleted), "include" (show all), "only" (show only deleted)',
|
|
63
|
+
},
|
|
57
64
|
},
|
|
58
65
|
},
|
|
59
66
|
};
|
|
@@ -67,6 +74,7 @@ export interface FindSimilarArgs {
|
|
|
67
74
|
limit?: number;
|
|
68
75
|
min_similarity?: number;
|
|
69
76
|
include_relationships?: boolean;
|
|
77
|
+
deleted_filter?: DeletedFilter;
|
|
70
78
|
}
|
|
71
79
|
|
|
72
80
|
/**
|
|
@@ -112,6 +120,9 @@ export async function handleFindSimilar(
|
|
|
112
120
|
const limit = args.limit ?? 10;
|
|
113
121
|
const minSimilarity = args.min_similarity ?? 0.7;
|
|
114
122
|
|
|
123
|
+
// Build deleted filter
|
|
124
|
+
const deletedFilter = buildDeletedFilter(collection, args.deleted_filter || 'exclude');
|
|
125
|
+
|
|
115
126
|
let results: any;
|
|
116
127
|
|
|
117
128
|
if (args.memory_id) {
|
|
@@ -136,21 +147,35 @@ export async function handleFindSimilar(
|
|
|
136
147
|
}
|
|
137
148
|
|
|
138
149
|
// Find similar using nearObject
|
|
139
|
-
|
|
150
|
+
const searchOptions: any = {
|
|
140
151
|
limit: limit + 1, // +1 to exclude the source memory itself
|
|
141
152
|
distance: 1 - minSimilarity, // Convert similarity to distance
|
|
142
153
|
returnMetadata: ['distance'],
|
|
143
|
-
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// Add deleted filter if present
|
|
157
|
+
if (deletedFilter) {
|
|
158
|
+
searchOptions.filters = deletedFilter;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
results = await collection.query.nearObject(args.memory_id, searchOptions);
|
|
144
162
|
|
|
145
163
|
// Filter out the source memory
|
|
146
164
|
results.objects = results.objects.filter((obj: any) => obj.uuid !== args.memory_id);
|
|
147
165
|
} else {
|
|
148
166
|
// Find similar to text
|
|
149
|
-
|
|
167
|
+
const searchOptions: any = {
|
|
150
168
|
limit: limit,
|
|
151
169
|
distance: 1 - minSimilarity,
|
|
152
170
|
returnMetadata: ['distance'],
|
|
153
|
-
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// Add deleted filter if present
|
|
174
|
+
if (deletedFilter) {
|
|
175
|
+
searchOptions.filters = deletedFilter;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
results = await collection.query.nearText(args.text!, searchOptions);
|
|
154
179
|
}
|
|
155
180
|
|
|
156
181
|
// Filter to only memories (not relationships) unless requested
|