@prmichaelsen/remember-mcp 2.2.1 → 2.3.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.
- package/AGENT.md +98 -5
- package/CHANGELOG.md +45 -0
- package/README.md +43 -3
- package/agent/commands/acp.init.md +376 -0
- package/agent/commands/acp.package-install.md +347 -0
- package/agent/commands/acp.proceed.md +311 -0
- package/agent/commands/acp.report.md +392 -0
- package/agent/commands/acp.status.md +280 -0
- package/agent/commands/acp.sync.md +323 -0
- package/agent/commands/acp.update.md +301 -0
- package/agent/commands/acp.validate.md +385 -0
- package/agent/commands/acp.version-check-for-updates.md +275 -0
- package/agent/commands/acp.version-check.md +190 -0
- package/agent/commands/acp.version-update.md +288 -0
- package/agent/commands/command.template.md +273 -0
- package/agent/design/core-memory-user-profile.md +1253 -0
- package/agent/design/ghost-profiles-pseudonymous-identity.md +194 -0
- package/agent/design/publish-tools-confirmation-flow.md +922 -0
- package/agent/milestones/milestone-10-shared-spaces.md +169 -0
- package/agent/progress.yaml +90 -4
- package/agent/scripts/install.sh +118 -0
- package/agent/scripts/update.sh +22 -10
- package/agent/scripts/version.sh +35 -0
- package/agent/tasks/task-27-implement-llm-provider-interface.md +51 -0
- package/agent/tasks/task-28-implement-llm-provider-factory.md +64 -0
- package/agent/tasks/task-29-update-config-for-llm.md +71 -0
- package/agent/tasks/task-30-implement-bedrock-provider.md +147 -0
- package/agent/tasks/task-31-implement-background-job-service.md +120 -0
- package/agent/tasks/task-32-test-llm-provider-integration.md +152 -0
- package/agent/tasks/task-34-create-confirmation-token-service.md +191 -0
- package/agent/tasks/task-35-create-space-memory-types-schema.md +183 -0
- package/agent/tasks/task-36-implement-remember-publish.md +227 -0
- package/agent/tasks/task-37-implement-remember-confirm.md +225 -0
- package/agent/tasks/task-38-implement-remember-deny.md +161 -0
- package/agent/tasks/task-39-implement-remember-search-space.md +188 -0
- package/agent/tasks/task-40-implement-remember-query-space.md +193 -0
- package/agent/tasks/task-41-configure-firestore-ttl.md +188 -0
- package/agent/tasks/task-42-create-tests-shared-spaces.md +216 -0
- package/agent/tasks/task-43-update-documentation.md +255 -0
- package/agent/tasks/task-44-implement-remember-retract.md +263 -0
- package/agent/tasks/task-45-fix-publish-false-success-bug.md +230 -0
- package/dist/llm/types.d.ts +1 -0
- package/dist/server-factory.js +1000 -1
- package/dist/server.js +1002 -3
- package/dist/services/confirmation-token.service.d.ts +99 -0
- package/dist/services/confirmation-token.service.spec.d.ts +5 -0
- package/dist/tools/confirm.d.ts +20 -0
- package/dist/tools/deny.d.ts +19 -0
- package/dist/tools/publish.d.ts +22 -0
- package/dist/tools/query-space.d.ts +28 -0
- package/dist/tools/search-space.d.ts +29 -0
- package/dist/types/space-memory.d.ts +80 -0
- package/dist/weaviate/space-schema.d.ts +59 -0
- package/dist/weaviate/space-schema.spec.d.ts +5 -0
- package/package.json +1 -1
- package/src/llm/types.ts +0 -0
- package/src/server-factory.ts +33 -0
- package/src/server.ts +33 -0
- package/src/services/confirmation-token.service.spec.ts +254 -0
- package/src/services/confirmation-token.service.ts +265 -0
- package/src/tools/confirm.ts +219 -0
- package/src/tools/create-memory.ts +7 -0
- package/src/tools/deny.ts +70 -0
- package/src/tools/publish.ts +190 -0
- package/src/tools/query-space.ts +197 -0
- package/src/tools/search-space.ts +189 -0
- package/src/types/space-memory.ts +94 -0
- package/src/weaviate/space-schema.spec.ts +131 -0
- package/src/weaviate/space-schema.ts +275 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* remember_confirm tool
|
|
3
|
+
*
|
|
4
|
+
* Generic confirmation tool that executes any pending action.
|
|
5
|
+
* This is the second phase of the confirmation workflow.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
9
|
+
import { confirmationTokenService, type ConfirmationRequest } from '../services/confirmation-token.service.js';
|
|
10
|
+
import { getWeaviateClient, getMemoryCollectionName } from '../weaviate/client.js';
|
|
11
|
+
import { ensureSpaceCollection } from '../weaviate/space-schema.js';
|
|
12
|
+
import { handleToolError } from '../utils/error-handler.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Tool definition for remember_confirm
|
|
16
|
+
*/
|
|
17
|
+
export const confirmTool: Tool = {
|
|
18
|
+
name: 'remember_confirm',
|
|
19
|
+
description: 'Confirm and execute a pending action using the token. Works for any action that requires confirmation (publish, delete, etc.).',
|
|
20
|
+
inputSchema: {
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: {
|
|
23
|
+
token: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
description: 'The confirmation token from the action tool',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
required: ['token'],
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
interface ConfirmArgs {
|
|
33
|
+
token: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Handle remember_confirm tool execution
|
|
38
|
+
*/
|
|
39
|
+
export async function handleConfirm(
|
|
40
|
+
args: ConfirmArgs,
|
|
41
|
+
userId: string
|
|
42
|
+
): Promise<string> {
|
|
43
|
+
try {
|
|
44
|
+
console.log('[remember_confirm] Starting confirmation:', {
|
|
45
|
+
userId,
|
|
46
|
+
token: args.token,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Validate and confirm token
|
|
50
|
+
const request = await confirmationTokenService.confirmRequest(userId, args.token);
|
|
51
|
+
|
|
52
|
+
console.log('[remember_confirm] Token validation result:', {
|
|
53
|
+
requestFound: !!request,
|
|
54
|
+
action: request?.action,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
if (!request) {
|
|
58
|
+
console.log('[remember_confirm] Token invalid or expired');
|
|
59
|
+
return JSON.stringify(
|
|
60
|
+
{
|
|
61
|
+
success: false,
|
|
62
|
+
error: 'Invalid or expired token',
|
|
63
|
+
message: 'The confirmation token is invalid, expired, or has already been used.',
|
|
64
|
+
},
|
|
65
|
+
null,
|
|
66
|
+
2
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
console.log('[remember_confirm] Executing action:', request.action);
|
|
71
|
+
|
|
72
|
+
// GENERIC: Execute action based on type
|
|
73
|
+
// This is where the generic pattern delegates to action-specific executors
|
|
74
|
+
if (request.action === 'publish_memory') {
|
|
75
|
+
return await executePublishMemory(request, userId);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Add other action types here as needed
|
|
79
|
+
// if (request.action === 'retract_memory') {
|
|
80
|
+
// return await executeRetractMemory(request, userId);
|
|
81
|
+
// }
|
|
82
|
+
|
|
83
|
+
throw new Error(`Unknown action type: ${request.action}`);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
handleToolError(error, {
|
|
86
|
+
toolName: 'remember_confirm',
|
|
87
|
+
userId,
|
|
88
|
+
operation: 'confirm action',
|
|
89
|
+
token: args.token,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Execute publish memory action
|
|
96
|
+
*/
|
|
97
|
+
async function executePublishMemory(
|
|
98
|
+
request: ConfirmationRequest & { request_id: string },
|
|
99
|
+
userId: string
|
|
100
|
+
): Promise<string> {
|
|
101
|
+
try {
|
|
102
|
+
console.log('[executePublishMemory] Starting execution:', {
|
|
103
|
+
userId,
|
|
104
|
+
memoryId: request.payload.memory_id,
|
|
105
|
+
targetSpace: request.target_collection,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Fetch the memory NOW (during confirmation, not from stored payload)
|
|
109
|
+
const weaviateClient = getWeaviateClient();
|
|
110
|
+
const userCollection = weaviateClient.collections.get(
|
|
111
|
+
getMemoryCollectionName(userId)
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
console.log('[executePublishMemory] Fetching original memory from:', getMemoryCollectionName(userId));
|
|
115
|
+
|
|
116
|
+
const originalMemory = await userCollection.query.fetchObjectById(
|
|
117
|
+
request.payload.memory_id
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
console.log('[executePublishMemory] Original memory fetch result:', {
|
|
121
|
+
found: !!originalMemory,
|
|
122
|
+
memoryId: request.payload.memory_id,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
if (!originalMemory) {
|
|
126
|
+
console.log('[executePublishMemory] Memory not found');
|
|
127
|
+
return JSON.stringify(
|
|
128
|
+
{
|
|
129
|
+
success: false,
|
|
130
|
+
error: 'Memory not found',
|
|
131
|
+
message: `Original memory ${request.payload.memory_id} no longer exists`,
|
|
132
|
+
},
|
|
133
|
+
null,
|
|
134
|
+
2
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Verify ownership again
|
|
139
|
+
if (originalMemory.properties.user_id !== userId) {
|
|
140
|
+
console.log('[executePublishMemory] Permission denied - wrong owner');
|
|
141
|
+
return JSON.stringify(
|
|
142
|
+
{
|
|
143
|
+
success: false,
|
|
144
|
+
error: 'Permission denied',
|
|
145
|
+
message: 'You can only publish your own memories',
|
|
146
|
+
},
|
|
147
|
+
null,
|
|
148
|
+
2
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
console.log('[executePublishMemory] Ensuring space collection:', request.target_collection || 'the_void');
|
|
153
|
+
|
|
154
|
+
// Get target collection
|
|
155
|
+
const targetCollection = await ensureSpaceCollection(
|
|
156
|
+
weaviateClient,
|
|
157
|
+
request.target_collection || 'the_void'
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
console.log('[executePublishMemory] Space collection ready');
|
|
161
|
+
|
|
162
|
+
// Create published memory (copy with modifications)
|
|
163
|
+
const originalTags = Array.isArray(originalMemory.properties.tags)
|
|
164
|
+
? originalMemory.properties.tags
|
|
165
|
+
: [];
|
|
166
|
+
const additionalTags = Array.isArray(request.payload.additional_tags)
|
|
167
|
+
? request.payload.additional_tags
|
|
168
|
+
: [];
|
|
169
|
+
|
|
170
|
+
const publishedMemory = {
|
|
171
|
+
...originalMemory.properties,
|
|
172
|
+
// Override specific fields
|
|
173
|
+
space_id: request.target_collection || 'the_void',
|
|
174
|
+
author_id: userId, // Always attributed
|
|
175
|
+
published_at: new Date().toISOString(),
|
|
176
|
+
discovery_count: 0,
|
|
177
|
+
doc_type: 'space_memory',
|
|
178
|
+
attribution: 'user' as const,
|
|
179
|
+
// Merge additional tags
|
|
180
|
+
tags: [...originalTags, ...additionalTags],
|
|
181
|
+
// Update timestamps
|
|
182
|
+
created_at: new Date().toISOString(),
|
|
183
|
+
updated_at: new Date().toISOString(),
|
|
184
|
+
version: 1,
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
console.log('[executePublishMemory] Inserting into space collection:', {
|
|
188
|
+
spaceId: request.target_collection || 'the_void',
|
|
189
|
+
memoryId: request.payload.memory_id,
|
|
190
|
+
hasProperties: !!publishedMemory,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const result = await targetCollection.data.insert({
|
|
194
|
+
properties: publishedMemory as any,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
console.log('[executePublishMemory] Insert result:', {
|
|
198
|
+
success: !!result,
|
|
199
|
+
spaceMemoryId: result,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Return minimal response - agent already knows original memory
|
|
203
|
+
return JSON.stringify(
|
|
204
|
+
{
|
|
205
|
+
success: true,
|
|
206
|
+
space_memory_id: result,
|
|
207
|
+
},
|
|
208
|
+
null,
|
|
209
|
+
2
|
|
210
|
+
);
|
|
211
|
+
} catch (error) {
|
|
212
|
+
handleToolError(error, {
|
|
213
|
+
toolName: 'remember_confirm',
|
|
214
|
+
userId,
|
|
215
|
+
operation: 'execute publish_memory',
|
|
216
|
+
action: 'publish_memory',
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
@@ -20,6 +20,13 @@ export const createMemoryTool = {
|
|
|
20
20
|
Each memory has a weight (significance 0-1) and trust level (access control 0-1).
|
|
21
21
|
Location and context are automatically captured from the request.
|
|
22
22
|
|
|
23
|
+
**IMPORTANT - Content vs Summary**:
|
|
24
|
+
- **content**: MUST be EXACT user-provided text. DO NOT paraphrase or modify.
|
|
25
|
+
- **summary**: Use for AI-generated summaries or interpretations.
|
|
26
|
+
- Example: User says "Remember: Meeting at 3pm tomorrow"
|
|
27
|
+
→ content: "Meeting at 3pm tomorrow" (EXACT)
|
|
28
|
+
→ summary: "User has meeting on 2026-02-17 at 15:00" (AI interpretation)
|
|
29
|
+
|
|
23
30
|
Examples:
|
|
24
31
|
- "Remember that I met Sarah at the conference"
|
|
25
32
|
- "Save this recipe for chocolate chip cookies"
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* remember_deny tool
|
|
3
|
+
*
|
|
4
|
+
* Generic denial tool for any pending action.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
+
import { confirmationTokenService } from '../services/confirmation-token.service.js';
|
|
9
|
+
import { handleToolError } from '../utils/error-handler.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Tool definition for remember_deny
|
|
13
|
+
*/
|
|
14
|
+
export const denyTool: Tool = {
|
|
15
|
+
name: 'remember_deny',
|
|
16
|
+
description: 'Deny a pending action. The request will be marked as denied and the token invalidated. Works for any action that requires confirmation.',
|
|
17
|
+
inputSchema: {
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: {
|
|
20
|
+
token: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
description: 'The confirmation token from the action tool',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
required: ['token'],
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
interface DenyArgs {
|
|
30
|
+
token: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Handle remember_deny tool execution
|
|
35
|
+
*/
|
|
36
|
+
export async function handleDeny(
|
|
37
|
+
args: DenyArgs,
|
|
38
|
+
userId: string
|
|
39
|
+
): Promise<string> {
|
|
40
|
+
try {
|
|
41
|
+
const success = await confirmationTokenService.denyRequest(userId, args.token);
|
|
42
|
+
|
|
43
|
+
if (!success) {
|
|
44
|
+
return JSON.stringify(
|
|
45
|
+
{
|
|
46
|
+
success: false,
|
|
47
|
+
error: 'Invalid token',
|
|
48
|
+
message: 'Token not found or already used',
|
|
49
|
+
},
|
|
50
|
+
null,
|
|
51
|
+
2
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return JSON.stringify(
|
|
56
|
+
{
|
|
57
|
+
success: true,
|
|
58
|
+
},
|
|
59
|
+
null,
|
|
60
|
+
2
|
|
61
|
+
);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
handleToolError(error, {
|
|
64
|
+
toolName: 'remember_deny',
|
|
65
|
+
userId,
|
|
66
|
+
operation: 'deny action',
|
|
67
|
+
token: args.token,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* remember_publish tool
|
|
3
|
+
*
|
|
4
|
+
* Generates a confirmation token for publishing a memory to a shared space.
|
|
5
|
+
* This is the first phase of the two-phase publish workflow.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
9
|
+
import { confirmationTokenService } from '../services/confirmation-token.service.js';
|
|
10
|
+
import { getWeaviateClient, getMemoryCollectionName } from '../weaviate/client.js';
|
|
11
|
+
import { isValidSpaceId } from '../weaviate/space-schema.js';
|
|
12
|
+
import { handleToolError } from '../utils/error-handler.js';
|
|
13
|
+
import { SUPPORTED_SPACES } from '../types/space-memory.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Tool definition for remember_publish
|
|
17
|
+
*/
|
|
18
|
+
export const publishTool: Tool = {
|
|
19
|
+
name: 'remember_publish',
|
|
20
|
+
description: 'Publish a memory to a shared space (like "The Void"). The memory will be COPIED (not moved) from your personal collection. Generates a confirmation token. Use remember_confirm to execute.',
|
|
21
|
+
inputSchema: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: {
|
|
24
|
+
memory_id: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
description: 'ID of the memory from your personal collection to publish',
|
|
27
|
+
},
|
|
28
|
+
target: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'Target space to publish to (snake_case ID)',
|
|
31
|
+
enum: SUPPORTED_SPACES,
|
|
32
|
+
default: 'the_void',
|
|
33
|
+
},
|
|
34
|
+
additional_tags: {
|
|
35
|
+
type: 'array',
|
|
36
|
+
items: { type: 'string' },
|
|
37
|
+
description: 'Additional tags for discovery (merged with original tags)',
|
|
38
|
+
default: [],
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
required: ['memory_id', 'target'],
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
interface PublishArgs {
|
|
46
|
+
memory_id: string;
|
|
47
|
+
target: string;
|
|
48
|
+
additional_tags?: string[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Handle remember_publish tool execution
|
|
53
|
+
*/
|
|
54
|
+
export async function handlePublish(
|
|
55
|
+
args: PublishArgs,
|
|
56
|
+
userId: string
|
|
57
|
+
): Promise<string> {
|
|
58
|
+
try {
|
|
59
|
+
console.log('[remember_publish] Starting publish request:', {
|
|
60
|
+
userId,
|
|
61
|
+
memoryId: args.memory_id,
|
|
62
|
+
target: args.target,
|
|
63
|
+
additionalTags: args.additional_tags?.length || 0,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Validate space ID
|
|
67
|
+
if (!isValidSpaceId(args.target)) {
|
|
68
|
+
console.log('[remember_publish] Invalid space ID:', args.target);
|
|
69
|
+
return JSON.stringify(
|
|
70
|
+
{
|
|
71
|
+
success: false,
|
|
72
|
+
error: 'Invalid space ID',
|
|
73
|
+
message: `Space "${args.target}" is not supported. Supported spaces: ${SUPPORTED_SPACES.join(', ')}`,
|
|
74
|
+
context: {
|
|
75
|
+
provided_space: args.target,
|
|
76
|
+
supported_spaces: SUPPORTED_SPACES,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
null,
|
|
80
|
+
2
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Verify memory exists and user owns it
|
|
85
|
+
const weaviateClient = getWeaviateClient();
|
|
86
|
+
const collectionName = getMemoryCollectionName(userId);
|
|
87
|
+
console.log('[remember_publish] Fetching memory from collection:', collectionName);
|
|
88
|
+
|
|
89
|
+
const userCollection = weaviateClient.collections.get(collectionName);
|
|
90
|
+
|
|
91
|
+
const memory = await userCollection.query.fetchObjectById(args.memory_id);
|
|
92
|
+
|
|
93
|
+
console.log('[remember_publish] Memory fetch result:', {
|
|
94
|
+
found: !!memory,
|
|
95
|
+
memoryId: args.memory_id,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
if (!memory) {
|
|
99
|
+
console.log('[remember_publish] Memory not found');
|
|
100
|
+
return JSON.stringify(
|
|
101
|
+
{
|
|
102
|
+
success: false,
|
|
103
|
+
error: 'Memory not found',
|
|
104
|
+
message: `No memory found with ID: ${args.memory_id}`,
|
|
105
|
+
context: {
|
|
106
|
+
collection_name: getMemoryCollectionName(userId),
|
|
107
|
+
memory_id: args.memory_id,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
null,
|
|
111
|
+
2
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Verify ownership
|
|
116
|
+
if (memory.properties.user_id !== userId) {
|
|
117
|
+
return JSON.stringify(
|
|
118
|
+
{
|
|
119
|
+
success: false,
|
|
120
|
+
error: 'Permission denied',
|
|
121
|
+
message: 'You can only publish your own memories',
|
|
122
|
+
context: {
|
|
123
|
+
memory_id: args.memory_id,
|
|
124
|
+
memory_owner: memory.properties.user_id,
|
|
125
|
+
requesting_user: userId,
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
null,
|
|
129
|
+
2
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Verify it's a memory (not a relationship)
|
|
134
|
+
if (memory.properties.doc_type !== 'memory') {
|
|
135
|
+
return JSON.stringify(
|
|
136
|
+
{
|
|
137
|
+
success: false,
|
|
138
|
+
error: 'Invalid document type',
|
|
139
|
+
message: 'Only memories can be published (not relationships)',
|
|
140
|
+
context: {
|
|
141
|
+
memory_id: args.memory_id,
|
|
142
|
+
doc_type: memory.properties.doc_type,
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
null,
|
|
146
|
+
2
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Create payload with only memory_id (content fetched during confirmation)
|
|
151
|
+
const payload = {
|
|
152
|
+
memory_id: args.memory_id,
|
|
153
|
+
additional_tags: args.additional_tags || [],
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
console.log('[remember_publish] Generating confirmation token');
|
|
157
|
+
|
|
158
|
+
// Generate confirmation token
|
|
159
|
+
const { requestId, token } = await confirmationTokenService.createRequest(
|
|
160
|
+
userId,
|
|
161
|
+
'publish_memory',
|
|
162
|
+
payload,
|
|
163
|
+
args.target
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
console.log('[remember_publish] Token generated:', {
|
|
167
|
+
requestId,
|
|
168
|
+
token,
|
|
169
|
+
action: 'publish_memory',
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Return minimal response - agent already knows memory details
|
|
173
|
+
return JSON.stringify(
|
|
174
|
+
{
|
|
175
|
+
success: true,
|
|
176
|
+
token,
|
|
177
|
+
},
|
|
178
|
+
null,
|
|
179
|
+
2
|
|
180
|
+
);
|
|
181
|
+
} catch (error) {
|
|
182
|
+
handleToolError(error, {
|
|
183
|
+
toolName: 'remember_publish',
|
|
184
|
+
userId,
|
|
185
|
+
operation: 'publish memory',
|
|
186
|
+
memory_id: args.memory_id,
|
|
187
|
+
target: args.target,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* remember_query_space tool
|
|
3
|
+
*
|
|
4
|
+
* RAG-optimized natural language queries for shared spaces.
|
|
5
|
+
* Similar to remember_query_memory but queries space collections.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
9
|
+
import { Filters } from 'weaviate-client';
|
|
10
|
+
import { getWeaviateClient } from '../weaviate/client.js';
|
|
11
|
+
import { ensureSpaceCollection, isValidSpaceId } from '../weaviate/space-schema.js';
|
|
12
|
+
import { SUPPORTED_SPACES } from '../types/space-memory.js';
|
|
13
|
+
import { handleToolError } from '../utils/error-handler.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Tool definition for remember_query_space
|
|
17
|
+
*/
|
|
18
|
+
export const querySpaceTool: Tool = {
|
|
19
|
+
name: 'remember_query_space',
|
|
20
|
+
description: 'Ask natural language questions about memories in shared spaces. Works like remember_query_memory but queries shared spaces.',
|
|
21
|
+
inputSchema: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: {
|
|
24
|
+
question: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
description: 'Natural language question',
|
|
27
|
+
},
|
|
28
|
+
space: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'Which space to query',
|
|
31
|
+
enum: SUPPORTED_SPACES,
|
|
32
|
+
default: 'the_void',
|
|
33
|
+
},
|
|
34
|
+
content_type: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
description: 'Filter by content type',
|
|
37
|
+
},
|
|
38
|
+
tags: {
|
|
39
|
+
type: 'array',
|
|
40
|
+
items: { type: 'string' },
|
|
41
|
+
description: 'Filter by tags',
|
|
42
|
+
},
|
|
43
|
+
min_weight: {
|
|
44
|
+
type: 'number',
|
|
45
|
+
minimum: 0,
|
|
46
|
+
maximum: 1,
|
|
47
|
+
description: 'Minimum weight/significance (0-1)',
|
|
48
|
+
},
|
|
49
|
+
date_from: {
|
|
50
|
+
type: 'string',
|
|
51
|
+
description: 'Filter memories created after this date (ISO 8601)',
|
|
52
|
+
},
|
|
53
|
+
date_to: {
|
|
54
|
+
type: 'string',
|
|
55
|
+
description: 'Filter memories created before this date (ISO 8601)',
|
|
56
|
+
},
|
|
57
|
+
limit: {
|
|
58
|
+
type: 'number',
|
|
59
|
+
default: 10,
|
|
60
|
+
description: 'Maximum number of results',
|
|
61
|
+
},
|
|
62
|
+
format: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
enum: ['detailed', 'compact'],
|
|
65
|
+
default: 'detailed',
|
|
66
|
+
description: 'Output format: detailed (full objects) or compact (text summary)',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
required: ['question', 'space'],
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
interface QuerySpaceArgs {
|
|
74
|
+
question: string;
|
|
75
|
+
space: string;
|
|
76
|
+
content_type?: string;
|
|
77
|
+
tags?: string[];
|
|
78
|
+
min_weight?: number;
|
|
79
|
+
date_from?: string;
|
|
80
|
+
date_to?: string;
|
|
81
|
+
limit?: number;
|
|
82
|
+
format?: 'detailed' | 'compact';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Handle remember_query_space tool execution
|
|
87
|
+
*/
|
|
88
|
+
export async function handleQuerySpace(
|
|
89
|
+
args: QuerySpaceArgs,
|
|
90
|
+
userId: string // May be used for private spaces in future
|
|
91
|
+
): Promise<string> {
|
|
92
|
+
try {
|
|
93
|
+
// Validate space ID
|
|
94
|
+
if (!isValidSpaceId(args.space)) {
|
|
95
|
+
return JSON.stringify(
|
|
96
|
+
{
|
|
97
|
+
success: false,
|
|
98
|
+
error: 'Invalid space ID',
|
|
99
|
+
message: `Space "${args.space}" is not supported. Supported spaces: ${SUPPORTED_SPACES.join(', ')}`,
|
|
100
|
+
},
|
|
101
|
+
null,
|
|
102
|
+
2
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const weaviateClient = getWeaviateClient();
|
|
107
|
+
const spaceCollection = await ensureSpaceCollection(weaviateClient, args.space);
|
|
108
|
+
|
|
109
|
+
// Build filters
|
|
110
|
+
const filterList: any[] = [];
|
|
111
|
+
|
|
112
|
+
// Filter by space_id
|
|
113
|
+
filterList.push(spaceCollection.filter.byProperty('space_id').equal(args.space));
|
|
114
|
+
|
|
115
|
+
// Filter by doc_type (space_memory)
|
|
116
|
+
filterList.push(spaceCollection.filter.byProperty('doc_type').equal('space_memory'));
|
|
117
|
+
|
|
118
|
+
// Apply content type filter
|
|
119
|
+
if (args.content_type) {
|
|
120
|
+
filterList.push(spaceCollection.filter.byProperty('type').equal(args.content_type));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Apply tags filter
|
|
124
|
+
if (args.tags && args.tags.length > 0) {
|
|
125
|
+
args.tags.forEach(tag => {
|
|
126
|
+
filterList.push(spaceCollection.filter.byProperty('tags').containsAny([tag]));
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Apply weight filter
|
|
131
|
+
if (args.min_weight !== undefined) {
|
|
132
|
+
filterList.push(spaceCollection.filter.byProperty('weight').greaterOrEqual(args.min_weight));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Apply date filters
|
|
136
|
+
if (args.date_from) {
|
|
137
|
+
filterList.push(spaceCollection.filter.byProperty('created_at').greaterOrEqual(new Date(args.date_from)));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (args.date_to) {
|
|
141
|
+
filterList.push(spaceCollection.filter.byProperty('created_at').lessOrEqual(new Date(args.date_to)));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const whereFilter = filterList.length > 0 ? Filters.and(...filterList) : undefined;
|
|
145
|
+
|
|
146
|
+
// Execute semantic search using nearText
|
|
147
|
+
const searchResults = await spaceCollection.query.nearText(args.question, {
|
|
148
|
+
limit: args.limit || 10,
|
|
149
|
+
...(whereFilter && { where: whereFilter }),
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Format results based on requested format
|
|
153
|
+
const format = args.format || 'detailed';
|
|
154
|
+
|
|
155
|
+
if (format === 'compact') {
|
|
156
|
+
// Compact format: text summary for LLM context
|
|
157
|
+
const summaries = searchResults.objects.map((obj, idx) => {
|
|
158
|
+
const props = obj.properties;
|
|
159
|
+
return `${idx + 1}. ${props.title || props.content?.substring(0, 100) || 'Untitled'}`;
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const result = {
|
|
163
|
+
question: args.question,
|
|
164
|
+
space: args.space,
|
|
165
|
+
format: 'compact',
|
|
166
|
+
summary: summaries.join('\n'),
|
|
167
|
+
count: searchResults.objects.length,
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
return JSON.stringify(result, null, 2);
|
|
171
|
+
} else {
|
|
172
|
+
// Detailed format: full objects
|
|
173
|
+
const memories = searchResults.objects.map((obj) => ({
|
|
174
|
+
id: obj.uuid,
|
|
175
|
+
...obj.properties,
|
|
176
|
+
_distance: obj.metadata?.distance,
|
|
177
|
+
}));
|
|
178
|
+
|
|
179
|
+
const result = {
|
|
180
|
+
question: args.question,
|
|
181
|
+
space: args.space,
|
|
182
|
+
format: 'detailed',
|
|
183
|
+
memories,
|
|
184
|
+
total: memories.length,
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
return JSON.stringify(result, null, 2);
|
|
188
|
+
}
|
|
189
|
+
} catch (error) {
|
|
190
|
+
handleToolError(error, {
|
|
191
|
+
toolName: 'remember_query_space',
|
|
192
|
+
operation: 'query space',
|
|
193
|
+
space: args.space,
|
|
194
|
+
question: args.question,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|