@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
@@ -4,12 +4,10 @@
4
4
  */
5
5
 
6
6
  import type { Memory, DeletedFilter } from '../types/memory.js';
7
- import { getMemoryCollection } from '../weaviate/schema.js';
8
- import { logger } from '../utils/logger.js';
9
7
  import { handleToolError } from '../utils/error-handler.js';
10
- import { buildDeletedFilter, combineFiltersWithAnd } from '../utils/weaviate-filters.js';
11
8
  import { createDebugLogger } from '../utils/debug.js';
12
9
  import type { AuthContext } from '../types/auth.js';
10
+ import { createCoreServices } from '../core-services.js';
13
11
 
14
12
  /**
15
13
  * Tool definition for remember_find_similar
@@ -111,122 +109,30 @@ export async function handleFindSimilar(
111
109
  try {
112
110
  debug.info('Tool invoked');
113
111
  debug.trace('Arguments', { args });
114
- logger.info('Finding similar memories', { userId, memoryId: args.memory_id, hasText: !!args.text });
115
112
 
116
- // Validate input
117
- if (!args.memory_id && !args.text) {
118
- throw new Error('Either memory_id or text must be provided');
119
- }
120
-
121
- if (args.memory_id && args.text) {
122
- throw new Error('Provide either memory_id or text, not both');
123
- }
124
-
125
- const collection = getMemoryCollection(userId);
126
- const limit = args.limit ?? 10;
127
- const minSimilarity = args.min_similarity ?? 0.7;
128
-
129
- // Build deleted filter
130
- const deletedFilter = buildDeletedFilter(collection, args.deleted_filter || 'exclude');
131
-
132
- // Exclude ghost memories by default
133
- const ghostExclusionFilter = collection.filter.byProperty('content_type').notEqual('ghost');
134
-
135
- // Combine filters
136
- const baseFilter = combineFiltersWithAnd([deletedFilter, ghostExclusionFilter].filter(f => f !== null));
137
-
138
- let results: any;
139
-
140
- if (args.memory_id) {
141
- // Find similar to existing memory
142
- // First get the memory to verify ownership
143
- const memory = await collection.query.fetchObjectById(args.memory_id, {
144
- returnProperties: ['user_id', 'doc_type', 'content'],
145
- });
146
-
147
- if (!memory) {
148
- throw new Error(`Memory not found: ${args.memory_id}`);
149
- }
150
-
151
- // Verify ownership
152
- if (memory.properties.user_id !== userId) {
153
- throw new Error('Unauthorized: Cannot access another user\'s memory');
154
- }
155
-
156
- // Verify it's a memory
157
- if (memory.properties.doc_type !== 'memory') {
158
- throw new Error('Can only find similar memories for memory documents, not relationships');
159
- }
160
-
161
- // Find similar using nearObject
162
- const searchOptions: any = {
163
- limit: limit + 1, // +1 to exclude the source memory itself
164
- distance: 1 - minSimilarity, // Convert similarity to distance
165
- returnMetadata: ['distance'],
166
- };
167
-
168
- // Add filters if present
169
- if (baseFilter) {
170
- searchOptions.filters = baseFilter;
171
- }
172
-
173
- results = await collection.query.nearObject(args.memory_id, searchOptions);
174
-
175
- // Filter out the source memory
176
- results.objects = results.objects.filter((obj: any) => obj.uuid !== args.memory_id);
177
- } else {
178
- // Find similar to text
179
- const searchOptions: any = {
180
- limit: limit,
181
- distance: 1 - minSimilarity,
182
- returnMetadata: ['distance'],
183
- };
184
-
185
- // Add filters if present
186
- if (baseFilter) {
187
- searchOptions.filters = baseFilter;
188
- }
189
-
190
- results = await collection.query.nearText(args.text!, searchOptions);
191
- }
192
-
193
- // Filter to only memories (not relationships) unless requested
194
- if (!args.include_relationships) {
195
- results.objects = results.objects.filter(
196
- (obj: any) => obj.properties.doc_type === 'memory'
197
- );
198
- }
199
-
200
- // Format results with similarity scores
201
- const similarMemories: SimilarMemory[] = results.objects.map((obj: any) => {
202
- const similarity = 1 - (obj.metadata?.distance ?? 0); // Convert distance back to similarity
203
- return {
204
- id: obj.uuid,
205
- ...obj.properties,
206
- similarity: Math.max(0, Math.min(1, similarity)), // Clamp to [0, 1]
207
- };
113
+ const { memory } = createCoreServices(userId);
114
+ const coreResult = await memory.findSimilar({
115
+ memory_id: args.memory_id,
116
+ text: args.text,
117
+ limit: args.limit,
118
+ min_similarity: args.min_similarity,
119
+ include_relationships: args.include_relationships,
120
+ deleted_filter: args.deleted_filter,
208
121
  });
209
122
 
210
- // Sort by similarity (highest first)
211
- similarMemories.sort((a, b) => (b.similarity ?? 0) - (a.similarity ?? 0));
212
-
213
- // Limit results
214
- const limitedResults = similarMemories.slice(0, limit);
215
-
216
- logger.info('Similar memories found', {
217
- userId,
218
- query: args.memory_id || args.text,
219
- results: limitedResults.length,
220
- });
123
+ // Post-filter ghost content (core doesn't exclude ghosts)
124
+ const filteredMemories = coreResult.similar_memories.filter(
125
+ (m: any) => m.content_type !== 'ghost'
126
+ );
221
127
 
222
128
  const result: FindSimilarResult = {
223
129
  query: {
224
130
  memory_id: args.memory_id,
225
131
  text: args.text,
226
132
  },
227
- similar_memories: limitedResults,
228
- total: limitedResults.length,
229
- min_similarity: minSimilarity,
133
+ similar_memories: filteredMemories as unknown as SimilarMemory[],
134
+ total: filteredMemories.length,
135
+ min_similarity: args.min_similarity ?? 0.7,
230
136
  };
231
137
 
232
138
  return JSON.stringify(result, null, 2);
@@ -3,8 +3,6 @@
3
3
  * Retrieve user preferences with defaults
4
4
  */
5
5
 
6
- import { PreferencesDatabaseService } from '../services/preferences-database.service.js';
7
- import { logger } from '../utils/logger.js';
8
6
  import { handleToolError } from '../utils/error-handler.js';
9
7
  import { createDebugLogger } from '../utils/debug.js';
10
8
  import {
@@ -14,6 +12,7 @@ import {
14
12
  getPreferenceDescription,
15
13
  } from '../types/preferences.js';
16
14
  import type { AuthContext } from '../types/auth.js';
15
+ import { createCoreServices } from '../core-services.js';
17
16
 
18
17
  /**
19
18
  * Tool definition for remember_get_preferences
@@ -74,10 +73,8 @@ export async function handleGetPreferences(
74
73
 
75
74
  const { category } = args;
76
75
 
77
- logger.info('Getting preferences', { userId, category });
78
-
79
- // Get preferences using service layer
80
- const preferences = await PreferencesDatabaseService.getPreferences(userId);
76
+ const { preferences: preferencesService } = createCoreServices(userId);
77
+ const preferences = await preferencesService.getPreferences(userId);
81
78
 
82
79
  // Check if these are defaults (no created_at means they were just generated)
83
80
  const isDefault = !preferences.created_at || preferences.created_at === preferences.updated_at;
@@ -110,8 +107,6 @@ export async function handleGetPreferences(
110
107
  message,
111
108
  };
112
109
 
113
- logger.info('Preferences retrieved successfully', { userId, category, isDefault });
114
-
115
110
  return JSON.stringify(response, null, 2);
116
111
  } catch (error) {
117
112
  debug.error('Tool failed', { error: error instanceof Error ? error.message : String(error) });
@@ -7,25 +7,8 @@ import type { AuthContext, GroupPermissions } from '../types/auth.js';
7
7
 
8
8
  // ─── Mocks ───────────────────────────────────────────────────
9
9
 
10
- const mockUpdate = jest.fn().mockResolvedValue(undefined);
11
-
12
- jest.mock('../weaviate/client.js', () => ({
13
- getWeaviateClient: jest.fn(() => ({
14
- collections: {
15
- get: jest.fn().mockReturnValue({
16
- data: { update: jest.fn().mockResolvedValue(undefined) },
17
- }),
18
- },
19
- })),
20
- fetchMemoryWithAllProperties: jest.fn(),
21
- }));
22
-
23
- jest.mock('../weaviate/space-schema.js', () => ({
24
- ensurePublicCollection: jest.fn(),
25
- }));
26
-
27
- jest.mock('../utils/logger.js', () => ({
28
- logger: { info: jest.fn(), debug: jest.fn(), warn: jest.fn(), error: jest.fn() },
10
+ jest.mock('../core-services.js', () => ({
11
+ createCoreServices: jest.fn(),
29
12
  }));
30
13
 
31
14
  jest.mock('../utils/debug.js', () => ({
@@ -38,21 +21,12 @@ jest.mock('../utils/debug.js', () => ({
38
21
  })),
39
22
  }));
40
23
 
41
- jest.mock('../collections/dot-notation.js', () => ({
42
- CollectionType: { GROUPS: 'groups' },
43
- getCollectionName: jest.fn((_: string, id: string) => `Memory_groups_${id}`),
44
- }));
45
-
46
24
  jest.mock('../utils/error-handler.js', () => ({
47
25
  handleToolError: jest.fn(() => '{"success":false,"error":"internal"}'),
48
26
  }));
49
27
 
50
- import { getWeaviateClient, fetchMemoryWithAllProperties } from '../weaviate/client.js';
51
- import { ensurePublicCollection } from '../weaviate/space-schema.js';
52
-
53
- const mockFetchMemory = fetchMemoryWithAllProperties as jest.MockedFunction<any>;
54
- const mockGetWeaviateClient = getWeaviateClient as jest.MockedFunction<any>;
55
- const mockEnsurePublicCollection = ensurePublicCollection as jest.MockedFunction<any>;
28
+ import { createCoreServices } from '../core-services.js';
29
+ const mockCreateCoreServices = createCoreServices as jest.MockedFunction<any>;
56
30
 
57
31
  // ─── Helpers ─────────────────────────────────────────────────
58
32
 
@@ -95,14 +69,6 @@ function makeNonModeratorAuth(): AuthContext {
95
69
  };
96
70
  }
97
71
 
98
- const PUBLISHED_MEMORY = {
99
- properties: {
100
- content: 'Published memory',
101
- moderation_status: 'pending',
102
- author_id: 'author-1',
103
- },
104
- };
105
-
106
72
  // ─── Tests ───────────────────────────────────────────────────
107
73
 
108
74
  describe('moderateTool definition', () => {
@@ -121,39 +87,28 @@ describe('moderateTool definition', () => {
121
87
  });
122
88
 
123
89
  describe('handleModerate', () => {
124
- let groupUpdate: jest.Mock;
125
- let spaceUpdate: jest.Mock;
90
+ let mockModerate: jest.Mock;
126
91
 
127
92
  beforeEach(() => {
128
93
  jest.clearAllMocks();
129
-
130
- groupUpdate = jest.fn().mockResolvedValue(undefined);
131
- spaceUpdate = jest.fn().mockResolvedValue(undefined);
132
-
133
- mockGetWeaviateClient.mockReturnValue({
134
- collections: {
135
- get: jest.fn().mockReturnValue({
136
- data: { update: groupUpdate },
137
- }),
138
- },
139
- });
140
-
141
- mockEnsurePublicCollection.mockResolvedValue({
142
- data: { update: spaceUpdate },
94
+ mockModerate = jest.fn();
95
+ mockCreateCoreServices.mockReturnValue({
96
+ space: { moderate: mockModerate },
143
97
  });
144
-
145
- mockFetchMemory.mockResolvedValue(PUBLISHED_MEMORY);
146
98
  });
147
99
 
148
- it('returns error when no space_id or group_id provided', async () => {
100
+ it('returns error when core throws for missing destination', async () => {
101
+ mockModerate.mockRejectedValue(new Error('Must specify either space_id or group_id'));
102
+
149
103
  const result = JSON.parse(
150
104
  await handleModerate({ memory_id: 'mem-1', action: 'approve' }, 'mod-1', makeModeratorAuth('g1'))
151
105
  );
152
106
  expect(result.success).toBe(false);
153
- expect(result.error).toBe('Missing destination');
154
107
  });
155
108
 
156
- it('returns permission error for non-moderator on group', async () => {
109
+ it('returns error when core throws for non-moderator on group', async () => {
110
+ mockModerate.mockRejectedValue(new Error('Permission denied'));
111
+
157
112
  const result = JSON.parse(
158
113
  await handleModerate(
159
114
  { memory_id: 'mem-1', action: 'approve', group_id: 'team-1' },
@@ -162,10 +117,11 @@ describe('handleModerate', () => {
162
117
  )
163
118
  );
164
119
  expect(result.success).toBe(false);
165
- expect(result.error).toBe('Permission denied');
166
120
  });
167
121
 
168
- it('returns permission error for non-moderator on space', async () => {
122
+ it('returns error when core throws for non-moderator on space', async () => {
123
+ mockModerate.mockRejectedValue(new Error('Permission denied'));
124
+
169
125
  const result = JSON.parse(
170
126
  await handleModerate(
171
127
  { memory_id: 'mem-1', action: 'approve', space_id: 'public' },
@@ -174,11 +130,10 @@ describe('handleModerate', () => {
174
130
  )
175
131
  );
176
132
  expect(result.success).toBe(false);
177
- expect(result.error).toBe('Permission denied');
178
133
  });
179
134
 
180
- it('returns error when memory not found', async () => {
181
- mockFetchMemory.mockResolvedValue(null);
135
+ it('returns error when core throws for memory not found', async () => {
136
+ mockModerate.mockRejectedValue(new Error('Memory not found'));
182
137
 
183
138
  const result = JSON.parse(
184
139
  await handleModerate(
@@ -188,10 +143,18 @@ describe('handleModerate', () => {
188
143
  )
189
144
  );
190
145
  expect(result.success).toBe(false);
191
- expect(result.error).toBe('Memory not found');
192
146
  });
193
147
 
194
148
  it('approves a memory in a group', async () => {
149
+ mockModerate.mockResolvedValue({
150
+ memory_id: 'mem-1',
151
+ action: 'approve',
152
+ moderation_status: 'approved',
153
+ moderated_by: 'mod-1',
154
+ moderated_at: new Date().toISOString(),
155
+ location: 'group:g1',
156
+ });
157
+
195
158
  const result = JSON.parse(
196
159
  await handleModerate(
197
160
  { memory_id: 'mem-1', action: 'approve', group_id: 'g1' },
@@ -203,17 +166,18 @@ describe('handleModerate', () => {
203
166
  expect(result.moderation_status).toBe('approved');
204
167
  expect(result.moderated_by).toBe('mod-1');
205
168
  expect(result.moderated_at).toBeDefined();
206
-
207
- expect(groupUpdate).toHaveBeenCalledWith({
208
- id: 'mem-1',
209
- properties: expect.objectContaining({
210
- moderation_status: 'approved',
211
- moderated_by: 'mod-1',
212
- }),
213
- });
214
169
  });
215
170
 
216
171
  it('rejects a memory in a group', async () => {
172
+ mockModerate.mockResolvedValue({
173
+ memory_id: 'mem-1',
174
+ action: 'reject',
175
+ moderation_status: 'rejected',
176
+ moderated_by: 'mod-1',
177
+ moderated_at: new Date().toISOString(),
178
+ location: 'group:g1',
179
+ });
180
+
217
181
  const result = JSON.parse(
218
182
  await handleModerate(
219
183
  { memory_id: 'mem-1', action: 'reject', group_id: 'g1', reason: 'Spam' },
@@ -227,6 +191,15 @@ describe('handleModerate', () => {
227
191
  });
228
192
 
229
193
  it('removes a memory in a group', async () => {
194
+ mockModerate.mockResolvedValue({
195
+ memory_id: 'mem-1',
196
+ action: 'remove',
197
+ moderation_status: 'removed',
198
+ moderated_by: 'mod-1',
199
+ moderated_at: new Date().toISOString(),
200
+ location: 'group:g1',
201
+ });
202
+
230
203
  const result = JSON.parse(
231
204
  await handleModerate(
232
205
  { memory_id: 'mem-1', action: 'remove', group_id: 'g1' },
@@ -239,6 +212,15 @@ describe('handleModerate', () => {
239
212
  });
240
213
 
241
214
  it('moderates a memory in a space', async () => {
215
+ mockModerate.mockResolvedValue({
216
+ memory_id: 'mem-1',
217
+ action: 'approve',
218
+ moderation_status: 'approved',
219
+ moderated_by: 'mod-1',
220
+ moderated_at: new Date().toISOString(),
221
+ location: 'space:public',
222
+ });
223
+
242
224
  const result = JSON.parse(
243
225
  await handleModerate(
244
226
  { memory_id: 'mem-1', action: 'approve', space_id: 'public' },
@@ -249,18 +231,20 @@ describe('handleModerate', () => {
249
231
  expect(result.success).toBe(true);
250
232
  expect(result.moderation_status).toBe('approved');
251
233
  expect(result.location).toBe('space:public');
252
-
253
- expect(spaceUpdate).toHaveBeenCalledWith({
254
- id: 'mem-1',
255
- properties: expect.objectContaining({
256
- moderation_status: 'approved',
257
- moderated_by: 'mod-1',
258
- }),
259
- });
260
234
  });
261
235
 
262
236
  it('sets moderated_at to a valid ISO date', async () => {
263
237
  const before = new Date().toISOString();
238
+ const moderatedAt = new Date().toISOString();
239
+
240
+ mockModerate.mockResolvedValue({
241
+ memory_id: 'mem-1',
242
+ action: 'approve',
243
+ moderation_status: 'approved',
244
+ moderated_by: 'mod-1',
245
+ moderated_at: moderatedAt,
246
+ location: 'group:g1',
247
+ });
264
248
 
265
249
  const result = JSON.parse(
266
250
  await handleModerate(
@@ -6,23 +6,13 @@
6
6
  */
7
7
 
8
8
  import type { Tool } from '@modelcontextprotocol/sdk/types.js';
9
- import { getWeaviateClient, fetchMemoryWithAllProperties } from '../weaviate/client.js';
10
- import { ensurePublicCollection } from '../weaviate/space-schema.js';
11
9
  import { handleToolError } from '../utils/error-handler.js';
12
10
  import { createDebugLogger } from '../utils/debug.js';
13
- import { logger } from '../utils/logger.js';
14
- import { CollectionType, getCollectionName } from '../collections/dot-notation.js';
15
11
  import type { AuthContext } from '../types/auth.js';
16
- import { canModerate, canModerateAny } from '../utils/auth-helpers.js';
12
+ import { createCoreServices } from '../core-services.js';
17
13
 
18
14
  type ModerationAction = 'approve' | 'reject' | 'remove';
19
15
 
20
- const ACTION_TO_STATUS: Record<ModerationAction, string> = {
21
- approve: 'approved',
22
- reject: 'rejected',
23
- remove: 'removed',
24
- };
25
-
26
16
  export const moderateTool: Tool = {
27
17
  name: 'remember_moderate',
28
18
  description: `Approve, reject, or remove a published memory. Requires moderator permissions (can_moderate).
@@ -85,121 +75,28 @@ export async function handleModerate(
85
75
  debug.info('Tool invoked');
86
76
  debug.trace('Arguments', { args });
87
77
 
88
- const { memory_id, space_id, group_id, action, reason } = args;
89
-
90
- // Validate: must specify either space_id or group_id
91
- if (!space_id && !group_id) {
92
- return JSON.stringify(
93
- {
94
- success: false,
95
- error: 'Missing destination',
96
- message: 'Must specify either space_id or group_id',
97
- },
98
- null,
99
- 2
100
- );
101
- }
102
-
103
- // Validate action
104
- if (!ACTION_TO_STATUS[action]) {
105
- return JSON.stringify(
106
- {
107
- success: false,
108
- error: 'Invalid action',
109
- message: `Action must be one of: approve, reject, remove`,
110
- },
111
- null,
112
- 2
113
- );
114
- }
115
-
116
- // Permission check
117
- if (group_id) {
118
- if (!canModerate(authContext, group_id)) {
119
- return JSON.stringify(
120
- {
121
- success: false,
122
- error: 'Permission denied',
123
- message: `Moderator access required for group ${group_id}`,
124
- },
125
- null,
126
- 2
127
- );
128
- }
129
- } else if (space_id) {
130
- if (!canModerateAny(authContext)) {
131
- return JSON.stringify(
132
- {
133
- success: false,
134
- error: 'Permission denied',
135
- message: `Moderator access required to moderate memories in spaces`,
136
- },
137
- null,
138
- 2
139
- );
140
- }
141
- }
142
-
143
- // Get the collection
144
- const weaviateClient = getWeaviateClient();
145
- let collection: any;
146
-
147
- if (group_id) {
148
- const collectionName = getCollectionName(CollectionType.GROUPS, group_id);
149
- collection = weaviateClient.collections.get(collectionName);
150
- } else {
151
- collection = await ensurePublicCollection(weaviateClient);
152
- }
153
-
154
- // Fetch the memory
155
- const memory = await fetchMemoryWithAllProperties(collection, memory_id);
156
-
157
- if (!memory) {
158
- return JSON.stringify(
159
- {
160
- success: false,
161
- error: 'Memory not found',
162
- message: `Published memory ${memory_id} not found in ${group_id ? `group ${group_id}` : `space ${space_id}`}`,
163
- },
164
- null,
165
- 2
166
- );
167
- }
168
-
169
- // Update moderation fields
170
- const newStatus = ACTION_TO_STATUS[action];
171
- const now = new Date().toISOString();
172
-
173
- await collection.data.update({
174
- id: memory_id,
175
- properties: {
176
- moderation_status: newStatus,
177
- moderated_by: userId,
178
- moderated_at: now,
78
+ const { space } = createCoreServices(userId);
79
+ const result = await space.moderate(
80
+ {
81
+ memory_id: args.memory_id,
82
+ space_id: args.space_id,
83
+ group_id: args.group_id,
84
+ action: args.action as any,
85
+ reason: args.reason,
179
86
  },
180
- });
181
-
182
- logger.info('Memory moderated', {
183
- tool: 'remember_moderate',
184
- userId,
185
- memoryId: memory_id,
186
- action,
187
- newStatus,
188
- spaceId: space_id,
189
- groupId: group_id,
190
- reason,
191
- });
87
+ authContext as any
88
+ );
192
89
 
193
90
  return JSON.stringify(
194
91
  {
195
92
  success: true,
196
- memory_id,
197
- action,
198
- moderation_status: newStatus,
199
- moderated_by: userId,
200
- moderated_at: now,
201
- reason: reason || undefined,
202
- location: group_id ? `group:${group_id}` : `space:${space_id}`,
93
+ memory_id: result.memory_id,
94
+ action: result.action,
95
+ moderation_status: result.moderation_status,
96
+ moderated_by: result.moderated_by,
97
+ moderated_at: result.moderated_at,
98
+ reason: args.reason || undefined,
99
+ location: result.location,
203
100
  },
204
101
  null,
205
102
  2