@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
package/dist/server.js
CHANGED
|
@@ -13,6 +13,9 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
13
13
|
return require.apply(this, arguments);
|
|
14
14
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
15
15
|
});
|
|
16
|
+
var __esm = (fn, res) => function __init() {
|
|
17
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
18
|
+
};
|
|
16
19
|
var __commonJS = (cb, mod) => function __require2() {
|
|
17
20
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
18
21
|
};
|
|
@@ -391,6 +394,15 @@ var require_main = __commonJS({
|
|
|
391
394
|
}
|
|
392
395
|
});
|
|
393
396
|
|
|
397
|
+
// src/types/space-memory.ts
|
|
398
|
+
var SUPPORTED_SPACES;
|
|
399
|
+
var init_space_memory = __esm({
|
|
400
|
+
"src/types/space-memory.ts"() {
|
|
401
|
+
"use strict";
|
|
402
|
+
SUPPORTED_SPACES = ["the_void"];
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
|
|
394
406
|
// src/server.ts
|
|
395
407
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
396
408
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -503,6 +515,9 @@ function sanitizeUserId(userId) {
|
|
|
503
515
|
}
|
|
504
516
|
return sanitized.charAt(0).toUpperCase() + sanitized.slice(1);
|
|
505
517
|
}
|
|
518
|
+
function getMemoryCollectionName(userId) {
|
|
519
|
+
return `Memory_${sanitizeUserId(userId)}`;
|
|
520
|
+
}
|
|
506
521
|
|
|
507
522
|
// src/firestore/init.ts
|
|
508
523
|
import { initializeApp } from "@prmichaelsen/firebase-admin-sdk-v8";
|
|
@@ -542,8 +557,8 @@ async function testFirestoreConnection() {
|
|
|
542
557
|
if (!initialized) {
|
|
543
558
|
throw new Error("Firestore not initialized");
|
|
544
559
|
}
|
|
545
|
-
const { getDocument:
|
|
546
|
-
await
|
|
560
|
+
const { getDocument: getDocument3 } = await import("@prmichaelsen/firebase-admin-sdk-v8");
|
|
561
|
+
await getDocument3("_health_check", "test");
|
|
547
562
|
console.log("[Firestore] Connection successful");
|
|
548
563
|
return true;
|
|
549
564
|
} catch (error) {
|
|
@@ -1238,6 +1253,13 @@ var createMemoryTool = {
|
|
|
1238
1253
|
Each memory has a weight (significance 0-1) and trust level (access control 0-1).
|
|
1239
1254
|
Location and context are automatically captured from the request.
|
|
1240
1255
|
|
|
1256
|
+
**IMPORTANT - Content vs Summary**:
|
|
1257
|
+
- **content**: MUST be EXACT user-provided text. DO NOT paraphrase or modify.
|
|
1258
|
+
- **summary**: Use for AI-generated summaries or interpretations.
|
|
1259
|
+
- Example: User says "Remember: Meeting at 3pm tomorrow"
|
|
1260
|
+
\u2192 content: "Meeting at 3pm tomorrow" (EXACT)
|
|
1261
|
+
\u2192 summary: "User has meeting on 2026-02-17 at 15:00" (AI interpretation)
|
|
1262
|
+
|
|
1241
1263
|
Examples:
|
|
1242
1264
|
- "Remember that I met Sarah at the conference"
|
|
1243
1265
|
- "Save this recipe for chocolate chip cookies"
|
|
@@ -3247,6 +3269,962 @@ async function handleGetPreferences(args, userId) {
|
|
|
3247
3269
|
}
|
|
3248
3270
|
}
|
|
3249
3271
|
|
|
3272
|
+
// src/services/confirmation-token.service.ts
|
|
3273
|
+
import { randomUUID } from "crypto";
|
|
3274
|
+
var ConfirmationTokenService = class {
|
|
3275
|
+
EXPIRY_MINUTES = 5;
|
|
3276
|
+
/**
|
|
3277
|
+
* Create a new confirmation request
|
|
3278
|
+
*
|
|
3279
|
+
* @param userId - User ID who initiated the request
|
|
3280
|
+
* @param action - Action type (e.g., 'publish_memory')
|
|
3281
|
+
* @param payload - Data to store with the request
|
|
3282
|
+
* @param targetCollection - Optional target collection (e.g., 'the_void')
|
|
3283
|
+
* @returns Request ID and token
|
|
3284
|
+
*/
|
|
3285
|
+
async createRequest(userId, action, payload, targetCollection) {
|
|
3286
|
+
const token = randomUUID();
|
|
3287
|
+
const now = /* @__PURE__ */ new Date();
|
|
3288
|
+
const expiresAt = new Date(now.getTime() + this.EXPIRY_MINUTES * 60 * 1e3);
|
|
3289
|
+
const request = {
|
|
3290
|
+
user_id: userId,
|
|
3291
|
+
token,
|
|
3292
|
+
action,
|
|
3293
|
+
target_collection: targetCollection,
|
|
3294
|
+
payload,
|
|
3295
|
+
created_at: now.toISOString(),
|
|
3296
|
+
expires_at: expiresAt.toISOString(),
|
|
3297
|
+
status: "pending"
|
|
3298
|
+
};
|
|
3299
|
+
const collectionPath = `users/${userId}/requests`;
|
|
3300
|
+
console.log("[ConfirmationTokenService] Creating request:", {
|
|
3301
|
+
userId,
|
|
3302
|
+
action,
|
|
3303
|
+
targetCollection,
|
|
3304
|
+
collectionPath
|
|
3305
|
+
});
|
|
3306
|
+
const docRef = await addDocument(collectionPath, request);
|
|
3307
|
+
console.log("[ConfirmationTokenService] Request created:", {
|
|
3308
|
+
requestId: docRef.id,
|
|
3309
|
+
token,
|
|
3310
|
+
expiresAt: request.expires_at
|
|
3311
|
+
});
|
|
3312
|
+
return { requestId: docRef.id, token };
|
|
3313
|
+
}
|
|
3314
|
+
/**
|
|
3315
|
+
* Validate and retrieve a confirmation request
|
|
3316
|
+
*
|
|
3317
|
+
* @param userId - User ID
|
|
3318
|
+
* @param token - Confirmation token
|
|
3319
|
+
* @returns Request with request_id if valid, null otherwise
|
|
3320
|
+
*/
|
|
3321
|
+
async validateToken(userId, token) {
|
|
3322
|
+
const collectionPath = `users/${userId}/requests`;
|
|
3323
|
+
console.log("[ConfirmationTokenService] Validating token:", {
|
|
3324
|
+
userId,
|
|
3325
|
+
token,
|
|
3326
|
+
collectionPath
|
|
3327
|
+
});
|
|
3328
|
+
const queryOptions = {
|
|
3329
|
+
where: [
|
|
3330
|
+
{ field: "token", op: "==", value: token },
|
|
3331
|
+
{ field: "status", op: "==", value: "pending" }
|
|
3332
|
+
],
|
|
3333
|
+
limit: 1
|
|
3334
|
+
};
|
|
3335
|
+
const results = await queryDocuments(collectionPath, queryOptions);
|
|
3336
|
+
console.log("[ConfirmationTokenService] Query results:", {
|
|
3337
|
+
resultsFound: results.length,
|
|
3338
|
+
hasResults: results.length > 0
|
|
3339
|
+
});
|
|
3340
|
+
if (results.length === 0) {
|
|
3341
|
+
console.log("[ConfirmationTokenService] Token not found or not pending");
|
|
3342
|
+
return null;
|
|
3343
|
+
}
|
|
3344
|
+
const doc = results[0];
|
|
3345
|
+
const request = doc.data;
|
|
3346
|
+
console.log("[ConfirmationTokenService] Request found:", {
|
|
3347
|
+
requestId: doc.id,
|
|
3348
|
+
action: request.action,
|
|
3349
|
+
status: request.status,
|
|
3350
|
+
expiresAt: request.expires_at
|
|
3351
|
+
});
|
|
3352
|
+
const expiresAt = new Date(request.expires_at);
|
|
3353
|
+
if (expiresAt.getTime() < Date.now()) {
|
|
3354
|
+
console.log("[ConfirmationTokenService] Token expired");
|
|
3355
|
+
await this.updateStatus(userId, doc.id, "expired");
|
|
3356
|
+
return null;
|
|
3357
|
+
}
|
|
3358
|
+
return {
|
|
3359
|
+
...request,
|
|
3360
|
+
request_id: doc.id
|
|
3361
|
+
};
|
|
3362
|
+
}
|
|
3363
|
+
/**
|
|
3364
|
+
* Confirm a request
|
|
3365
|
+
*
|
|
3366
|
+
* @param userId - User ID
|
|
3367
|
+
* @param token - Confirmation token
|
|
3368
|
+
* @returns Confirmed request if valid, null otherwise
|
|
3369
|
+
*/
|
|
3370
|
+
async confirmRequest(userId, token) {
|
|
3371
|
+
const request = await this.validateToken(userId, token);
|
|
3372
|
+
if (!request) {
|
|
3373
|
+
return null;
|
|
3374
|
+
}
|
|
3375
|
+
await this.updateStatus(userId, request.request_id, "confirmed");
|
|
3376
|
+
return {
|
|
3377
|
+
...request,
|
|
3378
|
+
status: "confirmed",
|
|
3379
|
+
confirmed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3380
|
+
};
|
|
3381
|
+
}
|
|
3382
|
+
/**
|
|
3383
|
+
* Deny a request
|
|
3384
|
+
*
|
|
3385
|
+
* @param userId - User ID
|
|
3386
|
+
* @param token - Confirmation token
|
|
3387
|
+
* @returns True if denied successfully, false otherwise
|
|
3388
|
+
*/
|
|
3389
|
+
async denyRequest(userId, token) {
|
|
3390
|
+
const request = await this.validateToken(userId, token);
|
|
3391
|
+
if (!request) {
|
|
3392
|
+
return false;
|
|
3393
|
+
}
|
|
3394
|
+
await this.updateStatus(userId, request.request_id, "denied");
|
|
3395
|
+
return true;
|
|
3396
|
+
}
|
|
3397
|
+
/**
|
|
3398
|
+
* Retract a request
|
|
3399
|
+
*
|
|
3400
|
+
* @param userId - User ID
|
|
3401
|
+
* @param token - Confirmation token
|
|
3402
|
+
* @returns True if retracted successfully, false otherwise
|
|
3403
|
+
*/
|
|
3404
|
+
async retractRequest(userId, token) {
|
|
3405
|
+
const request = await this.validateToken(userId, token);
|
|
3406
|
+
if (!request) {
|
|
3407
|
+
return false;
|
|
3408
|
+
}
|
|
3409
|
+
await this.updateStatus(userId, request.request_id, "retracted");
|
|
3410
|
+
return true;
|
|
3411
|
+
}
|
|
3412
|
+
/**
|
|
3413
|
+
* Update request status
|
|
3414
|
+
*
|
|
3415
|
+
* @param userId - User ID
|
|
3416
|
+
* @param requestId - Request document ID
|
|
3417
|
+
* @param status - New status
|
|
3418
|
+
*/
|
|
3419
|
+
async updateStatus(userId, requestId, status) {
|
|
3420
|
+
const collectionPath = `users/${userId}/requests`;
|
|
3421
|
+
const updateData = {
|
|
3422
|
+
status
|
|
3423
|
+
};
|
|
3424
|
+
if (status === "confirmed") {
|
|
3425
|
+
updateData.confirmed_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
3426
|
+
}
|
|
3427
|
+
await updateDocument(collectionPath, requestId, updateData);
|
|
3428
|
+
}
|
|
3429
|
+
/**
|
|
3430
|
+
* Clean up expired requests (optional - Firestore TTL handles deletion)
|
|
3431
|
+
*
|
|
3432
|
+
* Note: Configure Firestore TTL policy on 'requests' collection group
|
|
3433
|
+
* with 'expires_at' field for automatic deletion within 24 hours.
|
|
3434
|
+
*
|
|
3435
|
+
* This method is optional for immediate cleanup if needed.
|
|
3436
|
+
*
|
|
3437
|
+
* @returns Count of deleted requests
|
|
3438
|
+
*/
|
|
3439
|
+
async cleanupExpired() {
|
|
3440
|
+
console.warn("[ConfirmationTokenService] cleanupExpired not implemented - rely on Firestore TTL");
|
|
3441
|
+
return 0;
|
|
3442
|
+
}
|
|
3443
|
+
};
|
|
3444
|
+
var confirmationTokenService = new ConfirmationTokenService();
|
|
3445
|
+
|
|
3446
|
+
// src/weaviate/space-schema.ts
|
|
3447
|
+
init_space_memory();
|
|
3448
|
+
import weaviate3 from "weaviate-client";
|
|
3449
|
+
function getSpaceCollectionName(spaceId) {
|
|
3450
|
+
return `Memory_${spaceId}`;
|
|
3451
|
+
}
|
|
3452
|
+
function isValidSpaceId(spaceId) {
|
|
3453
|
+
return SUPPORTED_SPACES.includes(spaceId);
|
|
3454
|
+
}
|
|
3455
|
+
async function createSpaceCollection(client2, spaceId) {
|
|
3456
|
+
const collectionName = getSpaceCollectionName(spaceId);
|
|
3457
|
+
console.log(`[Weaviate] Creating space collection ${collectionName}...`);
|
|
3458
|
+
await client2.collections.create({
|
|
3459
|
+
name: collectionName,
|
|
3460
|
+
// Vectorizer configuration
|
|
3461
|
+
vectorizers: weaviate3.configure.vectorizer.text2VecOpenAI({
|
|
3462
|
+
model: "text-embedding-3-small",
|
|
3463
|
+
// Vectorize content for semantic search
|
|
3464
|
+
sourceProperties: ["content", "observation"]
|
|
3465
|
+
}),
|
|
3466
|
+
properties: [
|
|
3467
|
+
// Discriminator
|
|
3468
|
+
{
|
|
3469
|
+
name: "doc_type",
|
|
3470
|
+
dataType: "text",
|
|
3471
|
+
description: 'Document type: "space_memory"'
|
|
3472
|
+
},
|
|
3473
|
+
// Space identity
|
|
3474
|
+
{
|
|
3475
|
+
name: "space_id",
|
|
3476
|
+
dataType: "text",
|
|
3477
|
+
description: 'Space identifier (e.g., "the_void")'
|
|
3478
|
+
},
|
|
3479
|
+
{
|
|
3480
|
+
name: "author_id",
|
|
3481
|
+
dataType: "text",
|
|
3482
|
+
description: "Original author user_id (for permissions)"
|
|
3483
|
+
},
|
|
3484
|
+
{
|
|
3485
|
+
name: "ghost_id",
|
|
3486
|
+
dataType: "text",
|
|
3487
|
+
description: "Optional ghost profile ID for pseudonymous publishing"
|
|
3488
|
+
},
|
|
3489
|
+
{
|
|
3490
|
+
name: "attribution",
|
|
3491
|
+
dataType: "text",
|
|
3492
|
+
description: 'Attribution type: "user" or "ghost"'
|
|
3493
|
+
},
|
|
3494
|
+
// Discovery metadata
|
|
3495
|
+
{
|
|
3496
|
+
name: "published_at",
|
|
3497
|
+
dataType: "text",
|
|
3498
|
+
description: "When published to space (ISO 8601)"
|
|
3499
|
+
},
|
|
3500
|
+
{
|
|
3501
|
+
name: "discovery_count",
|
|
3502
|
+
dataType: "number",
|
|
3503
|
+
description: "How many times discovered"
|
|
3504
|
+
},
|
|
3505
|
+
// Memory fields (same as personal memories)
|
|
3506
|
+
{
|
|
3507
|
+
name: "content",
|
|
3508
|
+
dataType: "text",
|
|
3509
|
+
description: "Main memory content (vectorized)"
|
|
3510
|
+
},
|
|
3511
|
+
{
|
|
3512
|
+
name: "title",
|
|
3513
|
+
dataType: "text",
|
|
3514
|
+
description: "Optional short title"
|
|
3515
|
+
},
|
|
3516
|
+
{
|
|
3517
|
+
name: "summary",
|
|
3518
|
+
dataType: "text",
|
|
3519
|
+
description: "Optional brief summary"
|
|
3520
|
+
},
|
|
3521
|
+
{
|
|
3522
|
+
name: "type",
|
|
3523
|
+
dataType: "text",
|
|
3524
|
+
description: "Content type (note, event, person, etc.)"
|
|
3525
|
+
},
|
|
3526
|
+
// Scoring fields
|
|
3527
|
+
{
|
|
3528
|
+
name: "weight",
|
|
3529
|
+
dataType: "number",
|
|
3530
|
+
description: "Significance/priority (0-1)"
|
|
3531
|
+
},
|
|
3532
|
+
{
|
|
3533
|
+
name: "trust",
|
|
3534
|
+
dataType: "number",
|
|
3535
|
+
description: "Access control level (0-1)"
|
|
3536
|
+
},
|
|
3537
|
+
{
|
|
3538
|
+
name: "confidence",
|
|
3539
|
+
dataType: "number",
|
|
3540
|
+
description: "System confidence in accuracy (0-1)"
|
|
3541
|
+
},
|
|
3542
|
+
// Location fields (flattened)
|
|
3543
|
+
{
|
|
3544
|
+
name: "location_gps_latitude",
|
|
3545
|
+
dataType: "number",
|
|
3546
|
+
description: "GPS latitude"
|
|
3547
|
+
},
|
|
3548
|
+
{
|
|
3549
|
+
name: "location_gps_longitude",
|
|
3550
|
+
dataType: "number",
|
|
3551
|
+
description: "GPS longitude"
|
|
3552
|
+
},
|
|
3553
|
+
{
|
|
3554
|
+
name: "location_address_formatted",
|
|
3555
|
+
dataType: "text",
|
|
3556
|
+
description: "Formatted address"
|
|
3557
|
+
},
|
|
3558
|
+
{
|
|
3559
|
+
name: "location_address_city",
|
|
3560
|
+
dataType: "text",
|
|
3561
|
+
description: "City"
|
|
3562
|
+
},
|
|
3563
|
+
{
|
|
3564
|
+
name: "location_address_country",
|
|
3565
|
+
dataType: "text",
|
|
3566
|
+
description: "Country"
|
|
3567
|
+
},
|
|
3568
|
+
// Context fields (flattened)
|
|
3569
|
+
{
|
|
3570
|
+
name: "context_conversation_id",
|
|
3571
|
+
dataType: "text",
|
|
3572
|
+
description: "Conversation ID"
|
|
3573
|
+
},
|
|
3574
|
+
{
|
|
3575
|
+
name: "context_platform",
|
|
3576
|
+
dataType: "text",
|
|
3577
|
+
description: "Platform where created"
|
|
3578
|
+
},
|
|
3579
|
+
// Tags and relationships
|
|
3580
|
+
{
|
|
3581
|
+
name: "tags",
|
|
3582
|
+
dataType: "text[]",
|
|
3583
|
+
description: "Tags for categorization"
|
|
3584
|
+
},
|
|
3585
|
+
{
|
|
3586
|
+
name: "related_memory_ids",
|
|
3587
|
+
dataType: "text[]",
|
|
3588
|
+
description: "IDs of related memories"
|
|
3589
|
+
},
|
|
3590
|
+
// Timestamps
|
|
3591
|
+
{
|
|
3592
|
+
name: "created_at",
|
|
3593
|
+
dataType: "text",
|
|
3594
|
+
description: "Original creation timestamp (ISO 8601)"
|
|
3595
|
+
},
|
|
3596
|
+
{
|
|
3597
|
+
name: "updated_at",
|
|
3598
|
+
dataType: "text",
|
|
3599
|
+
description: "Last update timestamp (ISO 8601)"
|
|
3600
|
+
},
|
|
3601
|
+
// Versioning
|
|
3602
|
+
{
|
|
3603
|
+
name: "version",
|
|
3604
|
+
dataType: "number",
|
|
3605
|
+
description: "Version number (increments on update)"
|
|
3606
|
+
}
|
|
3607
|
+
]
|
|
3608
|
+
});
|
|
3609
|
+
console.log(`[Weaviate] Space collection ${collectionName} created successfully`);
|
|
3610
|
+
}
|
|
3611
|
+
async function ensureSpaceCollection(client2, spaceId) {
|
|
3612
|
+
if (!isValidSpaceId(spaceId)) {
|
|
3613
|
+
throw new Error(`Invalid space ID: ${spaceId}. Supported spaces: ${SUPPORTED_SPACES.join(", ")}`);
|
|
3614
|
+
}
|
|
3615
|
+
const collectionName = getSpaceCollectionName(spaceId);
|
|
3616
|
+
const exists = await client2.collections.exists(collectionName);
|
|
3617
|
+
if (!exists) {
|
|
3618
|
+
await createSpaceCollection(client2, spaceId);
|
|
3619
|
+
}
|
|
3620
|
+
return client2.collections.get(collectionName);
|
|
3621
|
+
}
|
|
3622
|
+
|
|
3623
|
+
// src/tools/publish.ts
|
|
3624
|
+
init_space_memory();
|
|
3625
|
+
var publishTool = {
|
|
3626
|
+
name: "remember_publish",
|
|
3627
|
+
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.',
|
|
3628
|
+
inputSchema: {
|
|
3629
|
+
type: "object",
|
|
3630
|
+
properties: {
|
|
3631
|
+
memory_id: {
|
|
3632
|
+
type: "string",
|
|
3633
|
+
description: "ID of the memory from your personal collection to publish"
|
|
3634
|
+
},
|
|
3635
|
+
target: {
|
|
3636
|
+
type: "string",
|
|
3637
|
+
description: "Target space to publish to (snake_case ID)",
|
|
3638
|
+
enum: SUPPORTED_SPACES,
|
|
3639
|
+
default: "the_void"
|
|
3640
|
+
},
|
|
3641
|
+
additional_tags: {
|
|
3642
|
+
type: "array",
|
|
3643
|
+
items: { type: "string" },
|
|
3644
|
+
description: "Additional tags for discovery (merged with original tags)",
|
|
3645
|
+
default: []
|
|
3646
|
+
}
|
|
3647
|
+
},
|
|
3648
|
+
required: ["memory_id", "target"]
|
|
3649
|
+
}
|
|
3650
|
+
};
|
|
3651
|
+
async function handlePublish(args, userId) {
|
|
3652
|
+
try {
|
|
3653
|
+
console.log("[remember_publish] Starting publish request:", {
|
|
3654
|
+
userId,
|
|
3655
|
+
memoryId: args.memory_id,
|
|
3656
|
+
target: args.target,
|
|
3657
|
+
additionalTags: args.additional_tags?.length || 0
|
|
3658
|
+
});
|
|
3659
|
+
if (!isValidSpaceId(args.target)) {
|
|
3660
|
+
console.log("[remember_publish] Invalid space ID:", args.target);
|
|
3661
|
+
return JSON.stringify(
|
|
3662
|
+
{
|
|
3663
|
+
success: false,
|
|
3664
|
+
error: "Invalid space ID",
|
|
3665
|
+
message: `Space "${args.target}" is not supported. Supported spaces: ${SUPPORTED_SPACES.join(", ")}`,
|
|
3666
|
+
context: {
|
|
3667
|
+
provided_space: args.target,
|
|
3668
|
+
supported_spaces: SUPPORTED_SPACES
|
|
3669
|
+
}
|
|
3670
|
+
},
|
|
3671
|
+
null,
|
|
3672
|
+
2
|
|
3673
|
+
);
|
|
3674
|
+
}
|
|
3675
|
+
const weaviateClient = getWeaviateClient();
|
|
3676
|
+
const collectionName = getMemoryCollectionName(userId);
|
|
3677
|
+
console.log("[remember_publish] Fetching memory from collection:", collectionName);
|
|
3678
|
+
const userCollection = weaviateClient.collections.get(collectionName);
|
|
3679
|
+
const memory = await userCollection.query.fetchObjectById(args.memory_id);
|
|
3680
|
+
console.log("[remember_publish] Memory fetch result:", {
|
|
3681
|
+
found: !!memory,
|
|
3682
|
+
memoryId: args.memory_id
|
|
3683
|
+
});
|
|
3684
|
+
if (!memory) {
|
|
3685
|
+
console.log("[remember_publish] Memory not found");
|
|
3686
|
+
return JSON.stringify(
|
|
3687
|
+
{
|
|
3688
|
+
success: false,
|
|
3689
|
+
error: "Memory not found",
|
|
3690
|
+
message: `No memory found with ID: ${args.memory_id}`,
|
|
3691
|
+
context: {
|
|
3692
|
+
collection_name: getMemoryCollectionName(userId),
|
|
3693
|
+
memory_id: args.memory_id
|
|
3694
|
+
}
|
|
3695
|
+
},
|
|
3696
|
+
null,
|
|
3697
|
+
2
|
|
3698
|
+
);
|
|
3699
|
+
}
|
|
3700
|
+
if (memory.properties.user_id !== userId) {
|
|
3701
|
+
return JSON.stringify(
|
|
3702
|
+
{
|
|
3703
|
+
success: false,
|
|
3704
|
+
error: "Permission denied",
|
|
3705
|
+
message: "You can only publish your own memories",
|
|
3706
|
+
context: {
|
|
3707
|
+
memory_id: args.memory_id,
|
|
3708
|
+
memory_owner: memory.properties.user_id,
|
|
3709
|
+
requesting_user: userId
|
|
3710
|
+
}
|
|
3711
|
+
},
|
|
3712
|
+
null,
|
|
3713
|
+
2
|
|
3714
|
+
);
|
|
3715
|
+
}
|
|
3716
|
+
if (memory.properties.doc_type !== "memory") {
|
|
3717
|
+
return JSON.stringify(
|
|
3718
|
+
{
|
|
3719
|
+
success: false,
|
|
3720
|
+
error: "Invalid document type",
|
|
3721
|
+
message: "Only memories can be published (not relationships)",
|
|
3722
|
+
context: {
|
|
3723
|
+
memory_id: args.memory_id,
|
|
3724
|
+
doc_type: memory.properties.doc_type
|
|
3725
|
+
}
|
|
3726
|
+
},
|
|
3727
|
+
null,
|
|
3728
|
+
2
|
|
3729
|
+
);
|
|
3730
|
+
}
|
|
3731
|
+
const payload = {
|
|
3732
|
+
memory_id: args.memory_id,
|
|
3733
|
+
additional_tags: args.additional_tags || []
|
|
3734
|
+
};
|
|
3735
|
+
console.log("[remember_publish] Generating confirmation token");
|
|
3736
|
+
const { requestId, token } = await confirmationTokenService.createRequest(
|
|
3737
|
+
userId,
|
|
3738
|
+
"publish_memory",
|
|
3739
|
+
payload,
|
|
3740
|
+
args.target
|
|
3741
|
+
);
|
|
3742
|
+
console.log("[remember_publish] Token generated:", {
|
|
3743
|
+
requestId,
|
|
3744
|
+
token,
|
|
3745
|
+
action: "publish_memory"
|
|
3746
|
+
});
|
|
3747
|
+
return JSON.stringify(
|
|
3748
|
+
{
|
|
3749
|
+
success: true,
|
|
3750
|
+
token
|
|
3751
|
+
},
|
|
3752
|
+
null,
|
|
3753
|
+
2
|
|
3754
|
+
);
|
|
3755
|
+
} catch (error) {
|
|
3756
|
+
handleToolError(error, {
|
|
3757
|
+
toolName: "remember_publish",
|
|
3758
|
+
userId,
|
|
3759
|
+
operation: "publish memory",
|
|
3760
|
+
memory_id: args.memory_id,
|
|
3761
|
+
target: args.target
|
|
3762
|
+
});
|
|
3763
|
+
}
|
|
3764
|
+
}
|
|
3765
|
+
|
|
3766
|
+
// src/tools/confirm.ts
|
|
3767
|
+
var confirmTool = {
|
|
3768
|
+
name: "remember_confirm",
|
|
3769
|
+
description: "Confirm and execute a pending action using the token. Works for any action that requires confirmation (publish, delete, etc.).",
|
|
3770
|
+
inputSchema: {
|
|
3771
|
+
type: "object",
|
|
3772
|
+
properties: {
|
|
3773
|
+
token: {
|
|
3774
|
+
type: "string",
|
|
3775
|
+
description: "The confirmation token from the action tool"
|
|
3776
|
+
}
|
|
3777
|
+
},
|
|
3778
|
+
required: ["token"]
|
|
3779
|
+
}
|
|
3780
|
+
};
|
|
3781
|
+
async function handleConfirm(args, userId) {
|
|
3782
|
+
try {
|
|
3783
|
+
console.log("[remember_confirm] Starting confirmation:", {
|
|
3784
|
+
userId,
|
|
3785
|
+
token: args.token
|
|
3786
|
+
});
|
|
3787
|
+
const request = await confirmationTokenService.confirmRequest(userId, args.token);
|
|
3788
|
+
console.log("[remember_confirm] Token validation result:", {
|
|
3789
|
+
requestFound: !!request,
|
|
3790
|
+
action: request?.action
|
|
3791
|
+
});
|
|
3792
|
+
if (!request) {
|
|
3793
|
+
console.log("[remember_confirm] Token invalid or expired");
|
|
3794
|
+
return JSON.stringify(
|
|
3795
|
+
{
|
|
3796
|
+
success: false,
|
|
3797
|
+
error: "Invalid or expired token",
|
|
3798
|
+
message: "The confirmation token is invalid, expired, or has already been used."
|
|
3799
|
+
},
|
|
3800
|
+
null,
|
|
3801
|
+
2
|
|
3802
|
+
);
|
|
3803
|
+
}
|
|
3804
|
+
console.log("[remember_confirm] Executing action:", request.action);
|
|
3805
|
+
if (request.action === "publish_memory") {
|
|
3806
|
+
return await executePublishMemory(request, userId);
|
|
3807
|
+
}
|
|
3808
|
+
throw new Error(`Unknown action type: ${request.action}`);
|
|
3809
|
+
} catch (error) {
|
|
3810
|
+
handleToolError(error, {
|
|
3811
|
+
toolName: "remember_confirm",
|
|
3812
|
+
userId,
|
|
3813
|
+
operation: "confirm action",
|
|
3814
|
+
token: args.token
|
|
3815
|
+
});
|
|
3816
|
+
}
|
|
3817
|
+
}
|
|
3818
|
+
async function executePublishMemory(request, userId) {
|
|
3819
|
+
try {
|
|
3820
|
+
console.log("[executePublishMemory] Starting execution:", {
|
|
3821
|
+
userId,
|
|
3822
|
+
memoryId: request.payload.memory_id,
|
|
3823
|
+
targetSpace: request.target_collection
|
|
3824
|
+
});
|
|
3825
|
+
const weaviateClient = getWeaviateClient();
|
|
3826
|
+
const userCollection = weaviateClient.collections.get(
|
|
3827
|
+
getMemoryCollectionName(userId)
|
|
3828
|
+
);
|
|
3829
|
+
console.log("[executePublishMemory] Fetching original memory from:", getMemoryCollectionName(userId));
|
|
3830
|
+
const originalMemory = await userCollection.query.fetchObjectById(
|
|
3831
|
+
request.payload.memory_id
|
|
3832
|
+
);
|
|
3833
|
+
console.log("[executePublishMemory] Original memory fetch result:", {
|
|
3834
|
+
found: !!originalMemory,
|
|
3835
|
+
memoryId: request.payload.memory_id
|
|
3836
|
+
});
|
|
3837
|
+
if (!originalMemory) {
|
|
3838
|
+
console.log("[executePublishMemory] Memory not found");
|
|
3839
|
+
return JSON.stringify(
|
|
3840
|
+
{
|
|
3841
|
+
success: false,
|
|
3842
|
+
error: "Memory not found",
|
|
3843
|
+
message: `Original memory ${request.payload.memory_id} no longer exists`
|
|
3844
|
+
},
|
|
3845
|
+
null,
|
|
3846
|
+
2
|
|
3847
|
+
);
|
|
3848
|
+
}
|
|
3849
|
+
if (originalMemory.properties.user_id !== userId) {
|
|
3850
|
+
console.log("[executePublishMemory] Permission denied - wrong owner");
|
|
3851
|
+
return JSON.stringify(
|
|
3852
|
+
{
|
|
3853
|
+
success: false,
|
|
3854
|
+
error: "Permission denied",
|
|
3855
|
+
message: "You can only publish your own memories"
|
|
3856
|
+
},
|
|
3857
|
+
null,
|
|
3858
|
+
2
|
|
3859
|
+
);
|
|
3860
|
+
}
|
|
3861
|
+
console.log("[executePublishMemory] Ensuring space collection:", request.target_collection || "the_void");
|
|
3862
|
+
const targetCollection = await ensureSpaceCollection(
|
|
3863
|
+
weaviateClient,
|
|
3864
|
+
request.target_collection || "the_void"
|
|
3865
|
+
);
|
|
3866
|
+
console.log("[executePublishMemory] Space collection ready");
|
|
3867
|
+
const originalTags = Array.isArray(originalMemory.properties.tags) ? originalMemory.properties.tags : [];
|
|
3868
|
+
const additionalTags = Array.isArray(request.payload.additional_tags) ? request.payload.additional_tags : [];
|
|
3869
|
+
const publishedMemory = {
|
|
3870
|
+
...originalMemory.properties,
|
|
3871
|
+
// Override specific fields
|
|
3872
|
+
space_id: request.target_collection || "the_void",
|
|
3873
|
+
author_id: userId,
|
|
3874
|
+
// Always attributed
|
|
3875
|
+
published_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3876
|
+
discovery_count: 0,
|
|
3877
|
+
doc_type: "space_memory",
|
|
3878
|
+
attribution: "user",
|
|
3879
|
+
// Merge additional tags
|
|
3880
|
+
tags: [...originalTags, ...additionalTags],
|
|
3881
|
+
// Update timestamps
|
|
3882
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3883
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3884
|
+
version: 1
|
|
3885
|
+
};
|
|
3886
|
+
console.log("[executePublishMemory] Inserting into space collection:", {
|
|
3887
|
+
spaceId: request.target_collection || "the_void",
|
|
3888
|
+
memoryId: request.payload.memory_id,
|
|
3889
|
+
hasProperties: !!publishedMemory
|
|
3890
|
+
});
|
|
3891
|
+
const result = await targetCollection.data.insert({
|
|
3892
|
+
properties: publishedMemory
|
|
3893
|
+
});
|
|
3894
|
+
console.log("[executePublishMemory] Insert result:", {
|
|
3895
|
+
success: !!result,
|
|
3896
|
+
spaceMemoryId: result
|
|
3897
|
+
});
|
|
3898
|
+
return JSON.stringify(
|
|
3899
|
+
{
|
|
3900
|
+
success: true,
|
|
3901
|
+
space_memory_id: result
|
|
3902
|
+
},
|
|
3903
|
+
null,
|
|
3904
|
+
2
|
|
3905
|
+
);
|
|
3906
|
+
} catch (error) {
|
|
3907
|
+
handleToolError(error, {
|
|
3908
|
+
toolName: "remember_confirm",
|
|
3909
|
+
userId,
|
|
3910
|
+
operation: "execute publish_memory",
|
|
3911
|
+
action: "publish_memory"
|
|
3912
|
+
});
|
|
3913
|
+
}
|
|
3914
|
+
}
|
|
3915
|
+
|
|
3916
|
+
// src/tools/deny.ts
|
|
3917
|
+
var denyTool = {
|
|
3918
|
+
name: "remember_deny",
|
|
3919
|
+
description: "Deny a pending action. The request will be marked as denied and the token invalidated. Works for any action that requires confirmation.",
|
|
3920
|
+
inputSchema: {
|
|
3921
|
+
type: "object",
|
|
3922
|
+
properties: {
|
|
3923
|
+
token: {
|
|
3924
|
+
type: "string",
|
|
3925
|
+
description: "The confirmation token from the action tool"
|
|
3926
|
+
}
|
|
3927
|
+
},
|
|
3928
|
+
required: ["token"]
|
|
3929
|
+
}
|
|
3930
|
+
};
|
|
3931
|
+
async function handleDeny(args, userId) {
|
|
3932
|
+
try {
|
|
3933
|
+
const success = await confirmationTokenService.denyRequest(userId, args.token);
|
|
3934
|
+
if (!success) {
|
|
3935
|
+
return JSON.stringify(
|
|
3936
|
+
{
|
|
3937
|
+
success: false,
|
|
3938
|
+
error: "Invalid token",
|
|
3939
|
+
message: "Token not found or already used"
|
|
3940
|
+
},
|
|
3941
|
+
null,
|
|
3942
|
+
2
|
|
3943
|
+
);
|
|
3944
|
+
}
|
|
3945
|
+
return JSON.stringify(
|
|
3946
|
+
{
|
|
3947
|
+
success: true
|
|
3948
|
+
},
|
|
3949
|
+
null,
|
|
3950
|
+
2
|
|
3951
|
+
);
|
|
3952
|
+
} catch (error) {
|
|
3953
|
+
handleToolError(error, {
|
|
3954
|
+
toolName: "remember_deny",
|
|
3955
|
+
userId,
|
|
3956
|
+
operation: "deny action",
|
|
3957
|
+
token: args.token
|
|
3958
|
+
});
|
|
3959
|
+
}
|
|
3960
|
+
}
|
|
3961
|
+
|
|
3962
|
+
// src/tools/search-space.ts
|
|
3963
|
+
import { Filters as Filters3 } from "weaviate-client";
|
|
3964
|
+
init_space_memory();
|
|
3965
|
+
var searchSpaceTool = {
|
|
3966
|
+
name: "remember_search_space",
|
|
3967
|
+
description: "Search shared spaces to discover thoughts, ideas, and memories. Works like remember_search_memory but searches shared spaces instead of personal memories.",
|
|
3968
|
+
inputSchema: {
|
|
3969
|
+
type: "object",
|
|
3970
|
+
properties: {
|
|
3971
|
+
query: {
|
|
3972
|
+
type: "string",
|
|
3973
|
+
description: "Search query (semantic + keyword hybrid)"
|
|
3974
|
+
},
|
|
3975
|
+
space: {
|
|
3976
|
+
type: "string",
|
|
3977
|
+
description: "Which space to search",
|
|
3978
|
+
enum: SUPPORTED_SPACES,
|
|
3979
|
+
default: "the_void"
|
|
3980
|
+
},
|
|
3981
|
+
content_type: {
|
|
3982
|
+
type: "string",
|
|
3983
|
+
description: "Filter by content type"
|
|
3984
|
+
},
|
|
3985
|
+
tags: {
|
|
3986
|
+
type: "array",
|
|
3987
|
+
items: { type: "string" },
|
|
3988
|
+
description: "Filter by tags (must have all specified tags)"
|
|
3989
|
+
},
|
|
3990
|
+
min_weight: {
|
|
3991
|
+
type: "number",
|
|
3992
|
+
minimum: 0,
|
|
3993
|
+
maximum: 1,
|
|
3994
|
+
description: "Minimum weight/significance (0-1)"
|
|
3995
|
+
},
|
|
3996
|
+
max_weight: {
|
|
3997
|
+
type: "number",
|
|
3998
|
+
minimum: 0,
|
|
3999
|
+
maximum: 1,
|
|
4000
|
+
description: "Maximum weight/significance (0-1)"
|
|
4001
|
+
},
|
|
4002
|
+
date_from: {
|
|
4003
|
+
type: "string",
|
|
4004
|
+
description: "Filter memories created after this date (ISO 8601)"
|
|
4005
|
+
},
|
|
4006
|
+
date_to: {
|
|
4007
|
+
type: "string",
|
|
4008
|
+
description: "Filter memories created before this date (ISO 8601)"
|
|
4009
|
+
},
|
|
4010
|
+
limit: {
|
|
4011
|
+
type: "number",
|
|
4012
|
+
default: 10,
|
|
4013
|
+
description: "Maximum number of results"
|
|
4014
|
+
},
|
|
4015
|
+
offset: {
|
|
4016
|
+
type: "number",
|
|
4017
|
+
default: 0,
|
|
4018
|
+
description: "Offset for pagination"
|
|
4019
|
+
}
|
|
4020
|
+
},
|
|
4021
|
+
required: ["query", "space"]
|
|
4022
|
+
}
|
|
4023
|
+
};
|
|
4024
|
+
async function handleSearchSpace(args, userId) {
|
|
4025
|
+
try {
|
|
4026
|
+
if (!isValidSpaceId(args.space)) {
|
|
4027
|
+
return JSON.stringify(
|
|
4028
|
+
{
|
|
4029
|
+
success: false,
|
|
4030
|
+
error: "Invalid space ID",
|
|
4031
|
+
message: `Space "${args.space}" is not supported. Supported spaces: ${SUPPORTED_SPACES.join(", ")}`
|
|
4032
|
+
},
|
|
4033
|
+
null,
|
|
4034
|
+
2
|
|
4035
|
+
);
|
|
4036
|
+
}
|
|
4037
|
+
const weaviateClient = getWeaviateClient();
|
|
4038
|
+
const spaceCollection = await ensureSpaceCollection(weaviateClient, args.space);
|
|
4039
|
+
const filterList = [];
|
|
4040
|
+
filterList.push(spaceCollection.filter.byProperty("space_id").equal(args.space));
|
|
4041
|
+
filterList.push(spaceCollection.filter.byProperty("doc_type").equal("space_memory"));
|
|
4042
|
+
if (args.content_type) {
|
|
4043
|
+
filterList.push(spaceCollection.filter.byProperty("type").equal(args.content_type));
|
|
4044
|
+
}
|
|
4045
|
+
if (args.tags && args.tags.length > 0) {
|
|
4046
|
+
args.tags.forEach((tag) => {
|
|
4047
|
+
filterList.push(spaceCollection.filter.byProperty("tags").containsAny([tag]));
|
|
4048
|
+
});
|
|
4049
|
+
}
|
|
4050
|
+
if (args.min_weight !== void 0) {
|
|
4051
|
+
filterList.push(spaceCollection.filter.byProperty("weight").greaterOrEqual(args.min_weight));
|
|
4052
|
+
}
|
|
4053
|
+
if (args.max_weight !== void 0) {
|
|
4054
|
+
filterList.push(spaceCollection.filter.byProperty("weight").lessOrEqual(args.max_weight));
|
|
4055
|
+
}
|
|
4056
|
+
if (args.date_from) {
|
|
4057
|
+
filterList.push(spaceCollection.filter.byProperty("created_at").greaterOrEqual(new Date(args.date_from)));
|
|
4058
|
+
}
|
|
4059
|
+
if (args.date_to) {
|
|
4060
|
+
filterList.push(spaceCollection.filter.byProperty("created_at").lessOrEqual(new Date(args.date_to)));
|
|
4061
|
+
}
|
|
4062
|
+
const whereFilter = filterList.length > 0 ? Filters3.and(...filterList) : void 0;
|
|
4063
|
+
const searchResults = await spaceCollection.query.hybrid(args.query, {
|
|
4064
|
+
limit: args.limit || 10,
|
|
4065
|
+
offset: args.offset || 0,
|
|
4066
|
+
...whereFilter && { where: whereFilter }
|
|
4067
|
+
});
|
|
4068
|
+
const memories = searchResults.objects.map((obj) => ({
|
|
4069
|
+
id: obj.uuid,
|
|
4070
|
+
...obj.properties,
|
|
4071
|
+
_score: obj.metadata?.score
|
|
4072
|
+
}));
|
|
4073
|
+
const result = {
|
|
4074
|
+
space: args.space,
|
|
4075
|
+
query: args.query,
|
|
4076
|
+
memories,
|
|
4077
|
+
total: memories.length,
|
|
4078
|
+
offset: args.offset || 0,
|
|
4079
|
+
limit: args.limit || 10
|
|
4080
|
+
};
|
|
4081
|
+
return JSON.stringify(result, null, 2);
|
|
4082
|
+
} catch (error) {
|
|
4083
|
+
handleToolError(error, {
|
|
4084
|
+
toolName: "remember_search_space",
|
|
4085
|
+
operation: "search space",
|
|
4086
|
+
space: args.space,
|
|
4087
|
+
query: args.query
|
|
4088
|
+
});
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
4091
|
+
|
|
4092
|
+
// src/tools/query-space.ts
|
|
4093
|
+
import { Filters as Filters4 } from "weaviate-client";
|
|
4094
|
+
init_space_memory();
|
|
4095
|
+
var querySpaceTool = {
|
|
4096
|
+
name: "remember_query_space",
|
|
4097
|
+
description: "Ask natural language questions about memories in shared spaces. Works like remember_query_memory but queries shared spaces.",
|
|
4098
|
+
inputSchema: {
|
|
4099
|
+
type: "object",
|
|
4100
|
+
properties: {
|
|
4101
|
+
question: {
|
|
4102
|
+
type: "string",
|
|
4103
|
+
description: "Natural language question"
|
|
4104
|
+
},
|
|
4105
|
+
space: {
|
|
4106
|
+
type: "string",
|
|
4107
|
+
description: "Which space to query",
|
|
4108
|
+
enum: SUPPORTED_SPACES,
|
|
4109
|
+
default: "the_void"
|
|
4110
|
+
},
|
|
4111
|
+
content_type: {
|
|
4112
|
+
type: "string",
|
|
4113
|
+
description: "Filter by content type"
|
|
4114
|
+
},
|
|
4115
|
+
tags: {
|
|
4116
|
+
type: "array",
|
|
4117
|
+
items: { type: "string" },
|
|
4118
|
+
description: "Filter by tags"
|
|
4119
|
+
},
|
|
4120
|
+
min_weight: {
|
|
4121
|
+
type: "number",
|
|
4122
|
+
minimum: 0,
|
|
4123
|
+
maximum: 1,
|
|
4124
|
+
description: "Minimum weight/significance (0-1)"
|
|
4125
|
+
},
|
|
4126
|
+
date_from: {
|
|
4127
|
+
type: "string",
|
|
4128
|
+
description: "Filter memories created after this date (ISO 8601)"
|
|
4129
|
+
},
|
|
4130
|
+
date_to: {
|
|
4131
|
+
type: "string",
|
|
4132
|
+
description: "Filter memories created before this date (ISO 8601)"
|
|
4133
|
+
},
|
|
4134
|
+
limit: {
|
|
4135
|
+
type: "number",
|
|
4136
|
+
default: 10,
|
|
4137
|
+
description: "Maximum number of results"
|
|
4138
|
+
},
|
|
4139
|
+
format: {
|
|
4140
|
+
type: "string",
|
|
4141
|
+
enum: ["detailed", "compact"],
|
|
4142
|
+
default: "detailed",
|
|
4143
|
+
description: "Output format: detailed (full objects) or compact (text summary)"
|
|
4144
|
+
}
|
|
4145
|
+
},
|
|
4146
|
+
required: ["question", "space"]
|
|
4147
|
+
}
|
|
4148
|
+
};
|
|
4149
|
+
async function handleQuerySpace(args, userId) {
|
|
4150
|
+
try {
|
|
4151
|
+
if (!isValidSpaceId(args.space)) {
|
|
4152
|
+
return JSON.stringify(
|
|
4153
|
+
{
|
|
4154
|
+
success: false,
|
|
4155
|
+
error: "Invalid space ID",
|
|
4156
|
+
message: `Space "${args.space}" is not supported. Supported spaces: ${SUPPORTED_SPACES.join(", ")}`
|
|
4157
|
+
},
|
|
4158
|
+
null,
|
|
4159
|
+
2
|
|
4160
|
+
);
|
|
4161
|
+
}
|
|
4162
|
+
const weaviateClient = getWeaviateClient();
|
|
4163
|
+
const spaceCollection = await ensureSpaceCollection(weaviateClient, args.space);
|
|
4164
|
+
const filterList = [];
|
|
4165
|
+
filterList.push(spaceCollection.filter.byProperty("space_id").equal(args.space));
|
|
4166
|
+
filterList.push(spaceCollection.filter.byProperty("doc_type").equal("space_memory"));
|
|
4167
|
+
if (args.content_type) {
|
|
4168
|
+
filterList.push(spaceCollection.filter.byProperty("type").equal(args.content_type));
|
|
4169
|
+
}
|
|
4170
|
+
if (args.tags && args.tags.length > 0) {
|
|
4171
|
+
args.tags.forEach((tag) => {
|
|
4172
|
+
filterList.push(spaceCollection.filter.byProperty("tags").containsAny([tag]));
|
|
4173
|
+
});
|
|
4174
|
+
}
|
|
4175
|
+
if (args.min_weight !== void 0) {
|
|
4176
|
+
filterList.push(spaceCollection.filter.byProperty("weight").greaterOrEqual(args.min_weight));
|
|
4177
|
+
}
|
|
4178
|
+
if (args.date_from) {
|
|
4179
|
+
filterList.push(spaceCollection.filter.byProperty("created_at").greaterOrEqual(new Date(args.date_from)));
|
|
4180
|
+
}
|
|
4181
|
+
if (args.date_to) {
|
|
4182
|
+
filterList.push(spaceCollection.filter.byProperty("created_at").lessOrEqual(new Date(args.date_to)));
|
|
4183
|
+
}
|
|
4184
|
+
const whereFilter = filterList.length > 0 ? Filters4.and(...filterList) : void 0;
|
|
4185
|
+
const searchResults = await spaceCollection.query.nearText(args.question, {
|
|
4186
|
+
limit: args.limit || 10,
|
|
4187
|
+
...whereFilter && { where: whereFilter }
|
|
4188
|
+
});
|
|
4189
|
+
const format = args.format || "detailed";
|
|
4190
|
+
if (format === "compact") {
|
|
4191
|
+
const summaries = searchResults.objects.map((obj, idx) => {
|
|
4192
|
+
const props = obj.properties;
|
|
4193
|
+
return `${idx + 1}. ${props.title || props.content?.substring(0, 100) || "Untitled"}`;
|
|
4194
|
+
});
|
|
4195
|
+
const result = {
|
|
4196
|
+
question: args.question,
|
|
4197
|
+
space: args.space,
|
|
4198
|
+
format: "compact",
|
|
4199
|
+
summary: summaries.join("\n"),
|
|
4200
|
+
count: searchResults.objects.length
|
|
4201
|
+
};
|
|
4202
|
+
return JSON.stringify(result, null, 2);
|
|
4203
|
+
} else {
|
|
4204
|
+
const memories = searchResults.objects.map((obj) => ({
|
|
4205
|
+
id: obj.uuid,
|
|
4206
|
+
...obj.properties,
|
|
4207
|
+
_distance: obj.metadata?.distance
|
|
4208
|
+
}));
|
|
4209
|
+
const result = {
|
|
4210
|
+
question: args.question,
|
|
4211
|
+
space: args.space,
|
|
4212
|
+
format: "detailed",
|
|
4213
|
+
memories,
|
|
4214
|
+
total: memories.length
|
|
4215
|
+
};
|
|
4216
|
+
return JSON.stringify(result, null, 2);
|
|
4217
|
+
}
|
|
4218
|
+
} catch (error) {
|
|
4219
|
+
handleToolError(error, {
|
|
4220
|
+
toolName: "remember_query_space",
|
|
4221
|
+
operation: "query space",
|
|
4222
|
+
space: args.space,
|
|
4223
|
+
question: args.question
|
|
4224
|
+
});
|
|
4225
|
+
}
|
|
4226
|
+
}
|
|
4227
|
+
|
|
3250
4228
|
// src/server.ts
|
|
3251
4229
|
async function initServer() {
|
|
3252
4230
|
logger.info("Initializing remember-mcp server...");
|
|
@@ -3293,7 +4271,13 @@ function registerHandlers(server) {
|
|
|
3293
4271
|
deleteRelationshipTool,
|
|
3294
4272
|
// Preference tools
|
|
3295
4273
|
setPreferenceTool,
|
|
3296
|
-
getPreferencesTool
|
|
4274
|
+
getPreferencesTool,
|
|
4275
|
+
// Space tools
|
|
4276
|
+
publishTool,
|
|
4277
|
+
confirmTool,
|
|
4278
|
+
denyTool,
|
|
4279
|
+
searchSpaceTool,
|
|
4280
|
+
querySpaceTool
|
|
3297
4281
|
]
|
|
3298
4282
|
};
|
|
3299
4283
|
});
|
|
@@ -3339,6 +4323,21 @@ function registerHandlers(server) {
|
|
|
3339
4323
|
case "remember_get_preferences":
|
|
3340
4324
|
result = await handleGetPreferences(args, userId);
|
|
3341
4325
|
break;
|
|
4326
|
+
case "remember_publish":
|
|
4327
|
+
result = await handlePublish(args, userId);
|
|
4328
|
+
break;
|
|
4329
|
+
case "remember_confirm":
|
|
4330
|
+
result = await handleConfirm(args, userId);
|
|
4331
|
+
break;
|
|
4332
|
+
case "remember_deny":
|
|
4333
|
+
result = await handleDeny(args, userId);
|
|
4334
|
+
break;
|
|
4335
|
+
case "remember_search_space":
|
|
4336
|
+
result = await handleSearchSpace(args, userId);
|
|
4337
|
+
break;
|
|
4338
|
+
case "remember_query_space":
|
|
4339
|
+
result = await handleQuerySpace(args, userId);
|
|
4340
|
+
break;
|
|
3342
4341
|
default:
|
|
3343
4342
|
throw new McpError(
|
|
3344
4343
|
ErrorCode.MethodNotFound,
|