@prmichaelsen/remember-mcp 3.13.0 → 3.14.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.
Files changed (62) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/agent/milestones/milestone-17-remember-core-migration.md +140 -0
  3. package/agent/progress.yaml +123 -6
  4. package/agent/tasks/milestone-17-remember-core-migration/task-193-foundation-setup.md +58 -0
  5. package/agent/tasks/milestone-17-remember-core-migration/task-194-migrate-relationship-tools.md +47 -0
  6. package/agent/tasks/milestone-17-remember-core-migration/task-195-migrate-preference-tools.md +34 -0
  7. package/agent/tasks/milestone-17-remember-core-migration/task-196-migrate-memory-tools.md +46 -0
  8. package/agent/tasks/milestone-17-remember-core-migration/task-197-migrate-space-confirmation-tools.md +49 -0
  9. package/agent/tasks/milestone-17-remember-core-migration/task-198-migrate-space-search-moderate.md +46 -0
  10. package/agent/tasks/milestone-17-remember-core-migration/task-199-migrate-delete-memory.md +43 -0
  11. package/agent/tasks/milestone-17-remember-core-migration/task-200-code-cleanup-verification.md +52 -0
  12. package/dist/core-services.d.ts +25 -0
  13. package/dist/server-factory.js +3208 -3978
  14. package/dist/server.js +3708 -4474
  15. package/dist/tools/confirm-publish-moderation.spec.d.ts +3 -2
  16. package/dist/tools/create-memory.d.ts +1 -1
  17. package/dist/tools/query-space.d.ts +1 -1
  18. package/dist/tools/search-space.d.ts +10 -14
  19. package/jest.config.js +11 -0
  20. package/package.json +3 -1
  21. package/src/core-services.ts +50 -0
  22. package/src/tools/confirm-publish-moderation.spec.ts +120 -176
  23. package/src/tools/confirm.ts +70 -1035
  24. package/src/tools/create-memory.ts +16 -67
  25. package/src/tools/create-relationship.ts +13 -181
  26. package/src/tools/delete-memory.ts +7 -72
  27. package/src/tools/delete-relationship.ts +7 -91
  28. package/src/tools/deny.ts +4 -14
  29. package/src/tools/find-similar.ts +16 -110
  30. package/src/tools/get-preferences.ts +3 -8
  31. package/src/tools/moderate.spec.ts +65 -81
  32. package/src/tools/moderate.ts +18 -121
  33. package/src/tools/publish.ts +7 -204
  34. package/src/tools/query-space.ts +28 -140
  35. package/src/tools/retract.ts +7 -185
  36. package/src/tools/revise.ts +4 -136
  37. package/src/tools/search-relationship.ts +17 -116
  38. package/src/tools/search-space.ts +58 -304
  39. package/src/tools/set-preference.ts +3 -8
  40. package/src/tools/update-memory.ts +22 -190
  41. package/src/tools/update-relationship.ts +16 -90
  42. package/src/v2-smoke.e2e.ts +3 -2
  43. package/dist/collections/composite-ids.d.ts +0 -106
  44. package/dist/collections/core-infrastructure.spec.d.ts +0 -11
  45. package/dist/collections/dot-notation.d.ts +0 -106
  46. package/dist/collections/tracking-arrays.d.ts +0 -176
  47. package/dist/constants/content-types.d.ts +0 -61
  48. package/dist/services/confirmation-token.service.d.ts +0 -99
  49. package/dist/services/confirmation-token.service.spec.d.ts +0 -5
  50. package/dist/services/preferences-database.service.d.ts +0 -22
  51. package/dist/services/space-config.service.d.ts +0 -23
  52. package/dist/services/space-config.service.spec.d.ts +0 -2
  53. package/src/collections/composite-ids.ts +0 -193
  54. package/src/collections/core-infrastructure.spec.ts +0 -353
  55. package/src/collections/dot-notation.ts +0 -212
  56. package/src/collections/tracking-arrays.ts +0 -298
  57. package/src/constants/content-types.ts +0 -490
  58. package/src/services/confirmation-token.service.spec.ts +0 -254
  59. package/src/services/confirmation-token.service.ts +0 -328
  60. package/src/services/preferences-database.service.ts +0 -120
  61. package/src/services/space-config.service.spec.ts +0 -102
  62. package/src/services/space-config.service.ts +0 -79
@@ -12,14 +12,11 @@
12
12
  */
13
13
 
14
14
  import type { Tool } from '@modelcontextprotocol/sdk/types.js';
15
- import { confirmationTokenService } from '../services/confirmation-token.service.js';
16
- import { getWeaviateClient, getMemoryCollectionName, fetchMemoryWithAllProperties } from '../weaviate/client.js';
17
- import { isValidSpaceId } from '../weaviate/space-schema.js';
18
15
  import { handleToolError } from '../utils/error-handler.js';
19
16
  import { SUPPORTED_SPACES } from '../types/space-memory.js';
20
- import { logger } from '../utils/logger.js';
21
17
  import { createDebugLogger } from '../utils/debug.js';
22
18
  import type { AuthContext } from '../types/auth.js';
19
+ import { createCoreServices } from '../core-services.js';
23
20
 
24
21
  /**
25
22
  * Tool definition for remember_publish
@@ -92,213 +89,19 @@ export async function handlePublish(
92
89
  try {
93
90
  debug.info('Tool invoked');
94
91
  debug.trace('Arguments', { args });
95
-
96
- // Normalize arrays (handle undefined)
97
- const spaces = args.spaces || [];
98
- const groups = args.groups || [];
99
-
100
- logger.info('Starting publish request', {
101
- tool: 'remember_publish',
102
- userId,
103
- memoryId: args.memory_id,
104
- spaces,
105
- groups,
106
- spaceCount: spaces.length,
107
- groupCount: groups.length,
108
- additionalTags: args.additional_tags?.length || 0,
109
- });
110
-
111
- // Validate that at least one destination is provided
112
- if (spaces.length === 0 && groups.length === 0) {
113
- logger.warn('No destinations provided', {
114
- tool: 'remember_publish',
115
- userId,
116
- });
117
- return JSON.stringify(
118
- {
119
- success: false,
120
- error: 'No destinations provided',
121
- message: 'Must specify at least one space or group to publish to',
122
- },
123
- null,
124
- 2
125
- );
126
- }
127
-
128
- // Validate all space IDs
129
- if (spaces.length > 0) {
130
- debug.debug('Validating space IDs', { spaces });
131
- const invalidSpaces = spaces.filter(s => !isValidSpaceId(s));
132
- if (invalidSpaces.length > 0) {
133
- debug.warn('Invalid space IDs detected', { invalidSpaces });
134
- logger.warn('Invalid space IDs provided', {
135
- tool: 'remember_publish',
136
- invalidSpaces,
137
- providedSpaces: spaces,
138
- });
139
- return JSON.stringify(
140
- {
141
- success: false,
142
- error: 'Invalid space IDs',
143
- message: `Invalid spaces: ${invalidSpaces.join(', ')}. Supported spaces: ${SUPPORTED_SPACES.join(', ')}`,
144
- context: {
145
- invalid_spaces: invalidSpaces,
146
- provided_spaces: spaces,
147
- supported_spaces: SUPPORTED_SPACES,
148
- },
149
- },
150
- null,
151
- 2
152
- );
153
- }
154
- }
155
-
156
- // Validate group IDs format (basic validation - no dots allowed)
157
- if (groups.length > 0) {
158
- debug.debug('Validating group IDs', { groups });
159
- const invalidGroups = groups.filter(g => !g || g.includes('.') || g.trim() === '');
160
- if (invalidGroups.length > 0) {
161
- debug.warn('Invalid group IDs detected', { invalidGroups });
162
- logger.warn('Invalid group IDs provided', {
163
- tool: 'remember_publish',
164
- invalidGroups,
165
- providedGroups: groups,
166
- });
167
- return JSON.stringify(
168
- {
169
- success: false,
170
- error: 'Invalid group IDs',
171
- message: 'Group IDs cannot be empty or contain dots',
172
- context: {
173
- invalid_groups: invalidGroups,
174
- provided_groups: groups,
175
- },
176
- },
177
- null,
178
- 2
179
- );
180
- }
181
- }
182
-
183
- // Verify memory exists and user owns it
184
- const weaviateClient = getWeaviateClient();
185
- const collectionName = getMemoryCollectionName(userId);
186
- logger.debug('Fetching memory from collection', {
187
- tool: 'remember_publish',
188
- collectionName,
189
- memoryId: args.memory_id,
190
- });
191
-
192
- const userCollection = weaviateClient.collections.get(collectionName);
193
-
194
- const memory = await debug.time('Fetch memory from user collection', async () => {
195
- return await fetchMemoryWithAllProperties(userCollection, args.memory_id);
196
- });
197
-
198
- logger.debug('Memory fetch result', {
199
- tool: 'remember_publish',
200
- found: !!memory,
201
- memoryId: args.memory_id,
202
- hasProperties: !!memory?.properties,
203
- propertyCount: memory?.properties ? Object.keys(memory.properties).length : 0,
204
- hasTitle: !!memory?.properties?.title,
205
- hasContent: !!memory?.properties?.content,
206
- });
207
-
208
- if (!memory) {
209
- logger.info('Memory not found', {
210
- tool: 'remember_publish',
211
- memoryId: args.memory_id,
212
- collectionName,
213
- });
214
- return JSON.stringify(
215
- {
216
- success: false,
217
- error: 'Memory not found',
218
- message: `No memory found with ID: ${args.memory_id}`,
219
- context: {
220
- collection_name: getMemoryCollectionName(userId),
221
- memory_id: args.memory_id,
222
- },
223
- },
224
- null,
225
- 2
226
- );
227
- }
228
92
 
229
- // Verify ownership
230
- if (memory.properties.user_id !== userId) {
231
- return JSON.stringify(
232
- {
233
- success: false,
234
- error: 'Permission denied',
235
- message: 'You can only publish your own memories',
236
- context: {
237
- memory_id: args.memory_id,
238
- memory_owner: memory.properties.user_id,
239
- requesting_user: userId,
240
- },
241
- },
242
- null,
243
- 2
244
- );
245
- }
246
-
247
- // Verify it's a memory (not a relationship)
248
- if (memory.properties.doc_type !== 'memory') {
249
- return JSON.stringify(
250
- {
251
- success: false,
252
- error: 'Invalid document type',
253
- message: 'Only memories can be published (not relationships)',
254
- context: {
255
- memory_id: args.memory_id,
256
- doc_type: memory.properties.doc_type,
257
- },
258
- },
259
- null,
260
- 2
261
- );
262
- }
263
-
264
- // Create payload with memory_id, spaces, and groups arrays
265
- const payload = {
93
+ const { space } = createCoreServices(userId);
94
+ const result = await space.publish({
266
95
  memory_id: args.memory_id,
267
- spaces: spaces,
268
- groups: groups,
269
- additional_tags: args.additional_tags || [],
270
- };
271
-
272
- logger.info('Generating confirmation token', {
273
- tool: 'remember_publish',
274
- userId,
275
- memoryId: args.memory_id,
276
- spaces: spaces,
277
- groups: groups,
278
- });
279
-
280
- // Generate confirmation token
281
- const { requestId, token} = await confirmationTokenService.createRequest(
282
- userId,
283
- 'publish_memory',
284
- payload,
285
- undefined // No single target_collection anymore
286
- );
287
-
288
- logger.info('Confirmation token generated', {
289
- tool: 'remember_publish',
290
- requestId,
291
- token,
292
- action: 'publish_memory',
293
- spaces: spaces,
294
- groups: groups,
96
+ spaces: args.spaces,
97
+ groups: args.groups,
98
+ additional_tags: args.additional_tags,
295
99
  });
296
100
 
297
- // Return minimal response - agent already knows memory details
298
101
  return JSON.stringify(
299
102
  {
300
103
  success: true,
301
- token,
104
+ token: result.token,
302
105
  },
303
106
  null,
304
107
  2
@@ -6,16 +6,13 @@
6
6
  */
7
7
 
8
8
  import type { Tool } from '@modelcontextprotocol/sdk/types.js';
9
- import { Filters } from 'weaviate-client';
10
- import { getWeaviateClient } from '../weaviate/client.js';
11
- import { ensurePublicCollection, isValidSpaceId } from '../weaviate/space-schema.js';
12
9
  import { SUPPORTED_SPACES } from '../types/space-memory.js';
13
10
  import { handleToolError } from '../utils/error-handler.js';
14
11
  import { createDebugLogger } from '../utils/debug.js';
15
12
  import type { AuthContext } from '../types/auth.js';
16
- import type { ModerationFilter } from './search-space.js';
17
- import { buildModerationFilter } from './search-space.js';
18
- import { canModerateAny } from '../utils/auth-helpers.js';
13
+ import { createCoreServices } from '../core-services.js';
14
+
15
+ export type ModerationFilter = 'approved' | 'pending' | 'rejected' | 'removed' | 'all';
19
16
 
20
17
  /**
21
18
  * Tool definition for remember_query_space
@@ -128,164 +125,55 @@ export async function handleQuerySpace(
128
125
  try {
129
126
  debug.info('Tool invoked');
130
127
  debug.trace('Arguments', { args });
131
-
132
- // Validate all space IDs
133
- debug.debug('Validating space IDs', { spaces: args.spaces });
134
- const invalidSpaces = args.spaces.filter(s => !isValidSpaceId(s));
135
- if (invalidSpaces.length > 0) {
136
- return JSON.stringify(
137
- {
138
- success: false,
139
- error: 'Invalid space IDs',
140
- message: `Invalid spaces: ${invalidSpaces.join(', ')}. Supported spaces: ${SUPPORTED_SPACES.join(', ')}`,
141
- },
142
- null,
143
- 2
144
- );
145
- }
146
-
147
- // Validate not empty
148
- if (args.spaces.length === 0) {
149
- return JSON.stringify(
150
- {
151
- success: false,
152
- error: 'Empty spaces array',
153
- message: 'Must specify at least one space to query',
154
- },
155
- null,
156
- 2
157
- );
158
- }
159
-
160
- // Permission check: non-approved moderation filters require moderator access
161
- const moderationFilterValue = args.moderation_filter || 'approved';
162
- if (moderationFilterValue !== 'approved' && !canModerateAny(authContext)) {
163
- return JSON.stringify(
164
- {
165
- success: false,
166
- error: 'Permission denied',
167
- message: `Moderator access required to view ${moderationFilterValue} memories in spaces`,
168
- },
169
- null,
170
- 2
171
- );
172
- }
173
-
174
- const weaviateClient = getWeaviateClient();
175
- const publicCollection = await ensurePublicCollection(weaviateClient);
176
-
177
- // Build filters
178
- const filterList: any[] = [];
179
128
 
180
- // Filter by spaces array (memory must be in at least one requested space)
181
- filterList.push(publicCollection.filter.byProperty('spaces').containsAny(args.spaces));
182
-
183
- // Filter by doc_type (memory) - space_memory concept was removed
184
- filterList.push(publicCollection.filter.byProperty('doc_type').equal('memory'));
185
-
186
- // Moderation status filter
187
- const moderationFilter = buildModerationFilter(publicCollection, args.moderation_filter);
188
- if (moderationFilter) {
189
- filterList.push(moderationFilter);
190
- }
191
-
192
- // Apply content type filter
193
- if (args.content_type) {
194
- filterList.push(publicCollection.filter.byProperty('content_type').equal(args.content_type));
195
- }
196
-
197
- // Exclude comments and ghost memories by default (unless explicitly included)
198
- if (!args.include_comments && !args.content_type) {
199
- // Only exclude comments if not filtering by content_type
200
- // (if content_type is set, user has explicit control)
201
- filterList.push(publicCollection.filter.byProperty('content_type').notEqual('comment'));
202
- }
203
- if (!args.content_type) {
204
- filterList.push(publicCollection.filter.byProperty('content_type').notEqual('ghost'));
205
- }
206
-
207
- // Apply tags filter
208
- if (args.tags && args.tags.length > 0) {
209
- args.tags.forEach(tag => {
210
- filterList.push(publicCollection.filter.byProperty('tags').containsAny([tag]));
211
- });
212
- }
213
-
214
- // Apply weight filter
215
- if (args.min_weight !== undefined) {
216
- filterList.push(publicCollection.filter.byProperty('weight').greaterOrEqual(args.min_weight));
217
- }
218
-
219
- // Apply date filters
220
- if (args.date_from) {
221
- filterList.push(publicCollection.filter.byProperty('created_at').greaterOrEqual(new Date(args.date_from)));
222
- }
223
-
224
- if (args.date_to) {
225
- filterList.push(publicCollection.filter.byProperty('created_at').lessOrEqual(new Date(args.date_to)));
226
- }
227
-
228
- const whereFilter = filterList.length > 0 ? Filters.and(...filterList) : undefined;
229
-
230
- debug.debug('Executing semantic query', {
231
- question: args.question,
232
- filterCount: filterList.length,
233
- limit: args.limit || 10,
234
- });
235
-
236
- // Execute semantic search using nearText
237
- const searchResults = await debug.time('Semantic query', async () => {
238
- return await publicCollection.query.nearText(args.question, {
239
- limit: args.limit || 10,
240
- ...(whereFilter && { where: whereFilter }),
241
- });
242
- });
243
-
244
- debug.debug('Query completed', {
245
- resultCount: searchResults.objects.length,
246
- format: args.format || 'detailed',
247
- });
129
+ const { space } = createCoreServices(userId);
130
+ const coreResult = await space.query(
131
+ {
132
+ question: args.question,
133
+ spaces: args.spaces,
134
+ content_type: args.content_type,
135
+ tags: args.tags,
136
+ min_weight: args.min_weight,
137
+ date_from: args.date_from,
138
+ date_to: args.date_to,
139
+ moderation_filter: args.moderation_filter as any,
140
+ include_comments: args.include_comments,
141
+ limit: args.limit,
142
+ },
143
+ authContext as any
144
+ );
248
145
 
249
146
  // Format results based on requested format
250
147
  const format = args.format || 'detailed';
251
148
 
252
149
  if (format === 'compact') {
253
- // Compact format: text summary for LLM context
254
- const summaries = searchResults.objects.map((obj: any, idx: number) => {
255
- const props = obj.properties;
256
- return `${idx + 1}. ${props.title || props.content?.substring(0, 100) || 'Untitled'}`;
150
+ const summaries = coreResult.memories.map((mem: any, idx: number) => {
151
+ return `${idx + 1}. ${mem.title || mem.content?.substring(0, 100) || 'Untitled'}`;
257
152
  });
258
153
 
259
154
  const result = {
260
155
  question: args.question,
261
- spaces_queried: args.spaces,
156
+ spaces_queried: coreResult.spaces_queried,
262
157
  format: 'compact',
263
158
  summary: summaries.join('\n'),
264
- count: searchResults.objects.length,
159
+ count: coreResult.memories.length,
265
160
  };
266
161
 
267
162
  return JSON.stringify(result, null, 2);
268
163
  } else {
269
- // Detailed format: full objects
270
- const memories = searchResults.objects.map((obj: any) => ({
271
- id: obj.uuid,
272
- ...obj.properties,
273
- _distance: obj.metadata?.distance,
274
- }));
275
-
276
164
  const result = {
277
165
  question: args.question,
278
- spaces_queried: args.spaces,
166
+ spaces_queried: coreResult.spaces_queried,
279
167
  format: 'detailed',
280
- memories,
281
- total: memories.length,
168
+ memories: coreResult.memories,
169
+ total: coreResult.total,
282
170
  };
283
171
 
284
172
  debug.info('Tool completed successfully', {
285
- resultCount: memories.length,
173
+ resultCount: coreResult.total,
286
174
  format: 'detailed',
287
175
  });
288
-
176
+
289
177
  return JSON.stringify(result, null, 2);
290
178
  }
291
179
  } catch (error) {
@@ -12,12 +12,10 @@
12
12
  */
13
13
 
14
14
  import type { Tool } from '@modelcontextprotocol/sdk/types.js';
15
- import { confirmationTokenService } from '../services/confirmation-token.service.js';
16
- import { getWeaviateClient, getMemoryCollectionName, fetchMemoryWithAllProperties } from '../weaviate/client.js';
17
15
  import { handleToolError } from '../utils/error-handler.js';
18
- import { logger } from '../utils/logger.js';
19
16
  import { createDebugLogger } from '../utils/debug.js';
20
17
  import type { AuthContext } from '../types/auth.js';
18
+ import { createCoreServices } from '../core-services.js';
21
19
 
22
20
  /**
23
21
  * Tool definition for remember_retract
@@ -83,195 +81,19 @@ export async function handleRetract(
83
81
  debug.info('Tool invoked');
84
82
  debug.trace('Arguments', { args });
85
83
 
86
- // Normalize arrays (handle undefined)
87
- const spaces = args.spaces || [];
88
- const groups = args.groups || [];
89
-
90
- logger.info('Starting retract request', {
91
- tool: 'remember_retract',
92
- userId,
93
- memoryId: args.memory_id,
94
- spaces,
95
- groups,
96
- spaceCount: spaces.length,
97
- groupCount: groups.length,
84
+ const { space } = createCoreServices(userId);
85
+ const result = await space.retract({
86
+ memory_id: args.memory_id,
87
+ spaces: args.spaces,
88
+ groups: args.groups,
98
89
  });
99
90
 
100
- // Validate that at least one destination is provided
101
- if (spaces.length === 0 && groups.length === 0) {
102
- logger.warn('No destinations provided for retraction', {
103
- tool: 'remember_retract',
104
- userId,
105
- });
106
- return JSON.stringify(
107
- {
108
- success: false,
109
- error: 'No destinations provided',
110
- message: 'Must specify at least one space or group to retract from',
111
- },
112
- null,
113
- 2
114
- );
115
- }
116
-
117
- // Validate group IDs (no dots allowed)
118
- if (groups.length > 0) {
119
- const invalidGroups = groups.filter(g => g.includes('.'));
120
- if (invalidGroups.length > 0) {
121
- logger.warn('Invalid group IDs detected', {
122
- tool: 'remember_retract',
123
- invalidGroups,
124
- });
125
- return JSON.stringify(
126
- {
127
- success: false,
128
- error: 'Invalid group IDs',
129
- message: `Group IDs cannot contain dots: ${invalidGroups.join(', ')}`,
130
- context: {
131
- invalid_groups: invalidGroups,
132
- },
133
- },
134
- null,
135
- 2
136
- );
137
- }
138
- }
139
-
140
- // Verify the memory exists and belongs to the user
141
- const weaviateClient = getWeaviateClient();
142
- const collectionName = getMemoryCollectionName(userId);
143
- const collection = weaviateClient.collections.get(collectionName);
144
-
145
- logger.debug('Fetching memory for retraction', {
146
- tool: 'remember_retract',
147
- collectionName,
148
- memoryId: args.memory_id,
149
- });
150
-
151
- const memory = await fetchMemoryWithAllProperties(collection, args.memory_id);
152
-
153
- if (!memory) {
154
- logger.info('Memory not found for retraction', {
155
- tool: 'remember_retract',
156
- memoryId: args.memory_id,
157
- });
158
- return JSON.stringify(
159
- {
160
- success: false,
161
- error: 'Memory not found',
162
- message: `Memory ${args.memory_id} does not exist`,
163
- },
164
- null,
165
- 2
166
- );
167
- }
168
-
169
- // Verify ownership
170
- if (memory.properties.user_id !== userId) {
171
- logger.warn('Permission denied - wrong owner', {
172
- tool: 'remember_retract',
173
- memoryId: args.memory_id,
174
- memoryOwner: memory.properties.user_id,
175
- requestingUser: userId,
176
- });
177
- return JSON.stringify(
178
- {
179
- success: false,
180
- error: 'Permission denied',
181
- message: 'You can only retract your own memories',
182
- },
183
- null,
184
- 2
185
- );
186
- }
187
-
188
- // Check current publication status
189
- const currentSpaceIds: string[] = Array.isArray(memory.properties.space_ids)
190
- ? memory.properties.space_ids
191
- : [];
192
- const currentGroupIds: string[] = Array.isArray(memory.properties.group_ids)
193
- ? memory.properties.group_ids
194
- : [];
195
-
196
- // Validate that memory is actually published to the specified destinations
197
- const notPublishedSpaces = spaces.filter(s => !currentSpaceIds.includes(s));
198
- const notPublishedGroups = groups.filter(g => !currentGroupIds.includes(g));
199
-
200
- if (notPublishedSpaces.length > 0 || notPublishedGroups.length > 0) {
201
- logger.warn('Memory not published to some destinations', {
202
- tool: 'remember_retract',
203
- notPublishedSpaces,
204
- notPublishedGroups,
205
- currentSpaceIds,
206
- currentGroupIds,
207
- });
208
- return JSON.stringify(
209
- {
210
- success: false,
211
- error: 'Not published to destinations',
212
- message: 'Memory is not published to some of the specified destinations',
213
- context: {
214
- not_published_spaces: notPublishedSpaces,
215
- not_published_groups: notPublishedGroups,
216
- current_spaces: currentSpaceIds,
217
- current_groups: currentGroupIds,
218
- },
219
- },
220
- null,
221
- 2
222
- );
223
- }
224
-
225
- // Create confirmation request
226
- const { requestId, token } = await confirmationTokenService.createRequest(
227
- userId,
228
- 'retract_memory',
229
- {
230
- memory_id: args.memory_id,
231
- spaces,
232
- groups,
233
- current_space_ids: currentSpaceIds,
234
- current_group_ids: currentGroupIds,
235
- }
236
- );
237
-
238
- logger.info('Retract confirmation request created', {
239
- tool: 'remember_retract',
240
- requestId,
241
- userId,
242
- memoryId: args.memory_id,
243
- spaces,
244
- groups,
245
- });
246
-
247
- // Build summary for user
248
- const destinations: string[] = [];
249
- if (spaces.length > 0) {
250
- destinations.push(`spaces: ${spaces.join(', ')}`);
251
- }
252
- if (groups.length > 0) {
253
- destinations.push(`groups: ${groups.join(', ')}`);
254
- }
255
-
256
91
  return JSON.stringify(
257
92
  {
258
93
  success: true,
259
- message: 'Retraction request created. Please confirm to proceed.',
94
+ token: result.token,
260
95
  action: 'retract_memory',
261
96
  memory_id: args.memory_id,
262
- destinations: destinations.join('; '),
263
- retraction_details: {
264
- spaces: spaces.length > 0 ? {
265
- action: 'orphan',
266
- description: 'Memory will remain in Memory_spaces_public with updated tracking arrays (removed from space_ids)',
267
- spaces,
268
- } : null,
269
- groups: groups.length > 0 ? {
270
- action: 'orphan',
271
- description: 'Memory will remain in Memory_groups_{groupId} with updated tracking arrays (removed from group_ids)',
272
- groups,
273
- } : null,
274
- },
275
97
  confirmation_required: true,
276
98
  },
277
99
  null,