@prmichaelsen/remember-mcp 0.1.0 → 0.2.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.
@@ -0,0 +1,230 @@
1
+ /**
2
+ * remember_update_memory tool
3
+ * Update an existing memory with partial updates
4
+ */
5
+
6
+ import type { Memory, MemoryUpdate } from '../types/memory.js';
7
+ import { getMemoryCollection } from '../weaviate/schema.js';
8
+ import { logger } from '../utils/logger.js';
9
+ import { isValidContentType } from '../constants/content-types.js';
10
+
11
+ /**
12
+ * Tool definition for remember_update_memory
13
+ */
14
+ export const updateMemoryTool = {
15
+ name: 'remember_update_memory',
16
+ description: `Update an existing memory with partial updates.
17
+
18
+ Supports updating any field except id, user_id, doc_type, created_at.
19
+ Version number is automatically incremented and updated_at is set.
20
+ Only provided fields are updated (partial updates supported).
21
+
22
+ Examples:
23
+ - "Update that camping note to add more details"
24
+ - "Change the weight of my recipe memory"
25
+ - "Add tags to the meeting note from yesterday"
26
+ `,
27
+ inputSchema: {
28
+ type: 'object',
29
+ properties: {
30
+ memory_id: {
31
+ type: 'string',
32
+ description: 'ID of the memory to update',
33
+ },
34
+ content: {
35
+ type: 'string',
36
+ description: 'Updated memory content',
37
+ },
38
+ title: {
39
+ type: 'string',
40
+ description: 'Updated title',
41
+ },
42
+ type: {
43
+ type: 'string',
44
+ description: 'Updated content type',
45
+ },
46
+ weight: {
47
+ type: 'number',
48
+ description: 'Updated significance/priority (0-1)',
49
+ minimum: 0,
50
+ maximum: 1,
51
+ },
52
+ trust: {
53
+ type: 'number',
54
+ description: 'Updated access control level (0-1)',
55
+ minimum: 0,
56
+ maximum: 1,
57
+ },
58
+ tags: {
59
+ type: 'array',
60
+ items: { type: 'string' },
61
+ description: 'Updated tags (replaces existing tags)',
62
+ },
63
+ references: {
64
+ type: 'array',
65
+ items: { type: 'string' },
66
+ description: 'Updated source URLs (replaces existing references)',
67
+ },
68
+ structured_content: {
69
+ type: 'object',
70
+ description: 'Updated structured content',
71
+ },
72
+ },
73
+ required: ['memory_id'],
74
+ },
75
+ };
76
+
77
+ /**
78
+ * Update memory arguments
79
+ */
80
+ export interface UpdateMemoryArgs {
81
+ memory_id: string;
82
+ content?: string;
83
+ title?: string;
84
+ type?: string;
85
+ weight?: number;
86
+ trust?: number;
87
+ tags?: string[];
88
+ references?: string[];
89
+ structured_content?: Record<string, any>;
90
+ }
91
+
92
+ /**
93
+ * Update memory result
94
+ */
95
+ export interface UpdateMemoryResult {
96
+ memory_id: string;
97
+ updated_at: string;
98
+ version: number;
99
+ updated_fields: string[];
100
+ message: string;
101
+ }
102
+
103
+ /**
104
+ * Handle remember_update_memory tool
105
+ */
106
+ export async function handleUpdateMemory(
107
+ args: UpdateMemoryArgs,
108
+ userId: string
109
+ ): Promise<string> {
110
+ try {
111
+ logger.info('Updating memory', { userId, memoryId: args.memory_id });
112
+
113
+ const collection = getMemoryCollection(userId);
114
+
115
+ // Get existing memory to verify ownership and get current version
116
+ const existingMemory = await collection.query.fetchObjectById(args.memory_id, {
117
+ returnProperties: ['user_id', 'doc_type', 'version', 'type', 'weight', 'base_weight'],
118
+ });
119
+
120
+ if (!existingMemory) {
121
+ throw new Error(`Memory not found: ${args.memory_id}`);
122
+ }
123
+
124
+ // Verify ownership
125
+ if (existingMemory.properties.user_id !== userId) {
126
+ throw new Error('Unauthorized: Cannot update another user\'s memory');
127
+ }
128
+
129
+ // Verify it's a memory (not a relationship)
130
+ if (existingMemory.properties.doc_type !== 'memory') {
131
+ throw new Error('Cannot update relationships using this tool. Use remember_update_relationship instead.');
132
+ }
133
+
134
+ // Build update object with only provided fields
135
+ const updates: Record<string, any> = {};
136
+ const updatedFields: string[] = [];
137
+
138
+ // Update content fields
139
+ if (args.content !== undefined) {
140
+ updates.content = args.content;
141
+ updatedFields.push('content');
142
+ }
143
+
144
+ if (args.title !== undefined) {
145
+ updates.title = args.title;
146
+ updates.summary = args.title; // Keep summary in sync with title
147
+ updatedFields.push('title');
148
+ }
149
+
150
+ if (args.type !== undefined) {
151
+ if (!isValidContentType(args.type)) {
152
+ throw new Error(`Invalid content type: ${args.type}`);
153
+ }
154
+ updates.type = args.type;
155
+ updatedFields.push('type');
156
+ }
157
+
158
+ // Update scoring fields
159
+ if (args.weight !== undefined) {
160
+ if (args.weight < 0 || args.weight > 1) {
161
+ throw new Error('Weight must be between 0 and 1');
162
+ }
163
+ updates.weight = args.weight;
164
+ updates.base_weight = args.weight;
165
+ updates.computed_weight = args.weight; // Recalculate if needed
166
+ updatedFields.push('weight');
167
+ }
168
+
169
+ if (args.trust !== undefined) {
170
+ if (args.trust < 0 || args.trust > 1) {
171
+ throw new Error('Trust must be between 0 and 1');
172
+ }
173
+ updates.trust = args.trust;
174
+ updatedFields.push('trust');
175
+ }
176
+
177
+ // Update organization fields
178
+ if (args.tags !== undefined) {
179
+ updates.tags = args.tags;
180
+ updatedFields.push('tags');
181
+ }
182
+
183
+ if (args.references !== undefined) {
184
+ updates.references = args.references;
185
+ updatedFields.push('references');
186
+ }
187
+
188
+ // Update structured content
189
+ if (args.structured_content !== undefined) {
190
+ updates.structured_content = args.structured_content;
191
+ updatedFields.push('structured_content');
192
+ }
193
+
194
+ // Check if any fields were provided
195
+ if (updatedFields.length === 0) {
196
+ throw new Error('No fields provided for update. At least one field must be specified.');
197
+ }
198
+
199
+ // Update metadata
200
+ const now = new Date().toISOString();
201
+ updates.updated_at = now;
202
+ updates.version = (existingMemory.properties.version as number) + 1;
203
+
204
+ // Perform update in Weaviate
205
+ await collection.data.update({
206
+ id: args.memory_id,
207
+ properties: updates,
208
+ });
209
+
210
+ logger.info('Memory updated successfully', {
211
+ userId,
212
+ memoryId: args.memory_id,
213
+ version: updates.version,
214
+ updatedFields,
215
+ });
216
+
217
+ const result: UpdateMemoryResult = {
218
+ memory_id: args.memory_id,
219
+ updated_at: now,
220
+ version: updates.version,
221
+ updated_fields: updatedFields,
222
+ message: `Memory updated successfully. Updated fields: ${updatedFields.join(', ')}`,
223
+ };
224
+
225
+ return JSON.stringify(result, null, 2);
226
+ } catch (error) {
227
+ logger.error('Failed to update memory:', error);
228
+ throw new Error(`Failed to update memory: ${error instanceof Error ? error.message : String(error)}`);
229
+ }
230
+ }
@@ -0,0 +1,189 @@
1
+ /**
2
+ * remember_update_relationship tool
3
+ * Update an existing relationship with partial updates
4
+ */
5
+
6
+ import type { RelationshipUpdate } from '../types/memory.js';
7
+ import { getMemoryCollection } from '../weaviate/schema.js';
8
+ import { logger } from '../utils/logger.js';
9
+
10
+ /**
11
+ * Tool definition for remember_update_relationship
12
+ */
13
+ export const updateRelationshipTool = {
14
+ name: 'remember_update_relationship',
15
+ description: `Update an existing relationship with partial updates.
16
+
17
+ Supports updating relationship_type, observation, strength, confidence, and tags.
18
+ Version number is automatically incremented and updated_at is set.
19
+ Only provided fields are updated (partial updates supported).
20
+
21
+ Examples:
22
+ - "Update that relationship to increase the strength"
23
+ - "Change the observation text for the camping relationship"
24
+ - "Add tags to the inspiration relationship"
25
+ `,
26
+ inputSchema: {
27
+ type: 'object',
28
+ properties: {
29
+ relationship_id: {
30
+ type: 'string',
31
+ description: 'ID of the relationship to update',
32
+ },
33
+ relationship_type: {
34
+ type: 'string',
35
+ description: 'Updated relationship type',
36
+ },
37
+ observation: {
38
+ type: 'string',
39
+ description: 'Updated observation/description',
40
+ },
41
+ strength: {
42
+ type: 'number',
43
+ description: 'Updated strength (0-1)',
44
+ minimum: 0,
45
+ maximum: 1,
46
+ },
47
+ confidence: {
48
+ type: 'number',
49
+ description: 'Updated confidence (0-1)',
50
+ minimum: 0,
51
+ maximum: 1,
52
+ },
53
+ tags: {
54
+ type: 'array',
55
+ items: { type: 'string' },
56
+ description: 'Updated tags (replaces existing tags)',
57
+ },
58
+ },
59
+ required: ['relationship_id'],
60
+ },
61
+ };
62
+
63
+ /**
64
+ * Update relationship arguments
65
+ */
66
+ export interface UpdateRelationshipArgs {
67
+ relationship_id: string;
68
+ relationship_type?: string;
69
+ observation?: string;
70
+ strength?: number;
71
+ confidence?: number;
72
+ tags?: string[];
73
+ }
74
+
75
+ /**
76
+ * Update relationship result
77
+ */
78
+ export interface UpdateRelationshipResult {
79
+ relationship_id: string;
80
+ updated_at: string;
81
+ version: number;
82
+ updated_fields: string[];
83
+ message: string;
84
+ }
85
+
86
+ /**
87
+ * Handle remember_update_relationship tool
88
+ */
89
+ export async function handleUpdateRelationship(
90
+ args: UpdateRelationshipArgs,
91
+ userId: string
92
+ ): Promise<string> {
93
+ try {
94
+ logger.info('Updating relationship', { userId, relationshipId: args.relationship_id });
95
+
96
+ const collection = getMemoryCollection(userId);
97
+
98
+ // Get existing relationship to verify ownership and get current version
99
+ const existingRelationship = await collection.query.fetchObjectById(args.relationship_id, {
100
+ returnProperties: ['user_id', 'doc_type', 'version', 'relationship_type', 'strength', 'confidence'],
101
+ });
102
+
103
+ if (!existingRelationship) {
104
+ throw new Error(`Relationship not found: ${args.relationship_id}`);
105
+ }
106
+
107
+ // Verify ownership
108
+ if (existingRelationship.properties.user_id !== userId) {
109
+ throw new Error('Unauthorized: Cannot update another user\'s relationship');
110
+ }
111
+
112
+ // Verify it's a relationship (not a memory)
113
+ if (existingRelationship.properties.doc_type !== 'relationship') {
114
+ throw new Error('Cannot update memories using this tool. Use remember_update_memory instead.');
115
+ }
116
+
117
+ // Build update object with only provided fields
118
+ const updates: Record<string, any> = {};
119
+ const updatedFields: string[] = [];
120
+
121
+ // Update relationship fields
122
+ if (args.relationship_type !== undefined) {
123
+ updates.relationship_type = args.relationship_type;
124
+ updatedFields.push('relationship_type');
125
+ }
126
+
127
+ if (args.observation !== undefined) {
128
+ updates.observation = args.observation;
129
+ updatedFields.push('observation');
130
+ }
131
+
132
+ if (args.strength !== undefined) {
133
+ if (args.strength < 0 || args.strength > 1) {
134
+ throw new Error('Strength must be between 0 and 1');
135
+ }
136
+ updates.strength = args.strength;
137
+ updatedFields.push('strength');
138
+ }
139
+
140
+ if (args.confidence !== undefined) {
141
+ if (args.confidence < 0 || args.confidence > 1) {
142
+ throw new Error('Confidence must be between 0 and 1');
143
+ }
144
+ updates.confidence = args.confidence;
145
+ updatedFields.push('confidence');
146
+ }
147
+
148
+ if (args.tags !== undefined) {
149
+ updates.tags = args.tags;
150
+ updatedFields.push('tags');
151
+ }
152
+
153
+ // Check if any fields were provided
154
+ if (updatedFields.length === 0) {
155
+ throw new Error('No fields provided for update. At least one field must be specified.');
156
+ }
157
+
158
+ // Update metadata
159
+ const now = new Date().toISOString();
160
+ updates.updated_at = now;
161
+ updates.version = (existingRelationship.properties.version as number) + 1;
162
+
163
+ // Perform update in Weaviate
164
+ await collection.data.update({
165
+ id: args.relationship_id,
166
+ properties: updates,
167
+ });
168
+
169
+ logger.info('Relationship updated successfully', {
170
+ userId,
171
+ relationshipId: args.relationship_id,
172
+ version: updates.version,
173
+ updatedFields,
174
+ });
175
+
176
+ const result: UpdateRelationshipResult = {
177
+ relationship_id: args.relationship_id,
178
+ updated_at: now,
179
+ version: updates.version,
180
+ updated_fields: updatedFields,
181
+ message: `Relationship updated successfully. Updated fields: ${updatedFields.join(', ')}`,
182
+ };
183
+
184
+ return JSON.stringify(result, null, 2);
185
+ } catch (error) {
186
+ logger.error('Failed to update relationship:', error);
187
+ throw new Error(`Failed to update relationship: ${error instanceof Error ? error.message : String(error)}`);
188
+ }
189
+ }