@prmichaelsen/remember-mcp 3.0.0 → 3.12.0
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 +296 -250
- package/CHANGELOG.md +338 -0
- package/README.md +68 -45
- package/agent/commands/acp.clarification-create.md +382 -0
- package/agent/commands/acp.project-info.md +309 -0
- package/agent/commands/acp.project-remove.md +379 -0
- package/agent/commands/acp.project-update.md +296 -0
- package/agent/commands/acp.task-create.md +17 -9
- package/agent/commands/git.commit.md +13 -1
- package/agent/design/comment-memory-type.md +2 -2
- package/agent/design/local.collaborative-memory-sync.md +265 -0
- package/agent/design/local.content-flags.md +210 -0
- package/agent/design/local.ghost-persona-system.md +273 -0
- package/agent/design/local.group-acl-integration.md +338 -0
- package/agent/design/local.memory-acl-schema.md +352 -0
- package/agent/design/local.memory-collection-pattern-v2.md +348 -0
- package/agent/design/local.moderation-and-space-config.md +257 -0
- package/agent/design/local.v2-api-reference.md +621 -0
- package/agent/design/local.v2-migration-guide.md +191 -0
- package/agent/design/local.v2-usage-examples.md +265 -0
- package/agent/design/permissions-storage-architecture.md +11 -3
- package/agent/design/trust-escalation-prevention.md +9 -2
- package/agent/design/trust-system-implementation.md +12 -3
- package/agent/milestones/milestone-14-memory-collection-v2.md +182 -0
- package/agent/milestones/milestone-15-moderation-space-config.md +126 -0
- package/agent/progress.yaml +628 -49
- package/agent/scripts/acp.common.sh +2 -0
- package/agent/scripts/acp.install.sh +11 -1
- package/agent/scripts/acp.package-install-optimized.sh +454 -0
- package/agent/scripts/acp.package-install.sh +247 -300
- package/agent/scripts/acp.project-info.sh +218 -0
- package/agent/scripts/acp.project-remove.sh +302 -0
- package/agent/scripts/acp.project-update.sh +296 -0
- package/agent/scripts/acp.yaml-parser.sh +128 -10
- package/agent/tasks/milestone-14-memory-collection-v2/task-165-core-infrastructure-setup.md +171 -0
- package/agent/tasks/milestone-14-memory-collection-v2/task-166-update-remember-publish.md +191 -0
- package/agent/tasks/milestone-14-memory-collection-v2/task-167-update-remember-retract.md +186 -0
- package/agent/tasks/milestone-14-memory-collection-v2/task-168-implement-remember-revise.md +184 -0
- package/agent/tasks/milestone-14-memory-collection-v2/task-169-update-remember-search-space.md +179 -0
- package/agent/tasks/milestone-14-memory-collection-v2/task-170-update-remember-create-update.md +139 -0
- package/agent/tasks/milestone-14-memory-collection-v2/task-172-performance-testing-optimization.md +161 -0
- package/agent/tasks/milestone-14-memory-collection-v2/task-173-documentation-examples.md +258 -0
- package/agent/tasks/milestone-15-moderation-space-config/task-174-add-moderation-schema-fields.md +57 -0
- package/agent/tasks/milestone-15-moderation-space-config/task-175-create-space-config-service.md +64 -0
- package/agent/tasks/milestone-15-moderation-space-config/task-176-wire-moderation-publish-flow.md +45 -0
- package/agent/tasks/milestone-15-moderation-space-config/task-177-add-moderation-search-filters.md +70 -0
- package/agent/tasks/milestone-15-moderation-space-config/task-178-create-remember-moderate-tool.md +69 -0
- package/agent/tasks/milestone-15-moderation-space-config/task-179-documentation-integration-tests.md +58 -0
- package/agent/tasks/milestone-16-ghost-system/task-187-ghost-config-firestore.md +41 -0
- package/agent/tasks/milestone-16-ghost-system/task-188-trust-filter-integration.md +44 -0
- package/agent/tasks/milestone-16-ghost-system/task-189-ghost-memory-filtering.md +43 -0
- package/agent/tasks/milestone-16-ghost-system/task-190-ghost-config-tools.md +45 -0
- package/agent/tasks/milestone-16-ghost-system/task-191-escalation-firestore.md +38 -0
- package/agent/tasks/milestone-16-ghost-system/task-192-documentation-verification.md +39 -0
- package/agent/tasks/milestone-7-trust-permissions/task-180-access-result-permission-types.md +69 -0
- package/agent/tasks/milestone-7-trust-permissions/task-181-firestore-permissions-access-logs.md +56 -0
- package/agent/tasks/milestone-7-trust-permissions/task-182-trust-enforcement-service.md +68 -0
- package/agent/tasks/milestone-7-trust-permissions/task-183-access-control-service.md +70 -0
- package/agent/tasks/milestone-7-trust-permissions/task-184-permission-tools.md +79 -0
- package/agent/tasks/milestone-7-trust-permissions/task-185-wire-trust-into-search-query.md +55 -0
- package/agent/tasks/milestone-7-trust-permissions/task-186-documentation-verification.md +56 -0
- package/agent/tasks/task-76-fix-indexnullstate-schema-bug.md +197 -0
- package/dist/collections/composite-ids.d.ts +106 -0
- package/dist/collections/core-infrastructure.spec.d.ts +11 -0
- package/dist/collections/dot-notation.d.ts +106 -0
- package/dist/collections/tracking-arrays.d.ts +176 -0
- package/dist/constants/content-types.d.ts +1 -0
- package/dist/schema/v2-collections-comments.spec.d.ts +8 -0
- package/dist/schema/v2-collections.d.ts +210 -0
- package/dist/server-factory.d.ts +15 -0
- package/dist/server-factory.js +2798 -1029
- package/dist/server.js +2526 -1012
- package/dist/services/access-control.d.ts +103 -0
- package/dist/services/access-control.spec.d.ts +2 -0
- package/dist/services/credentials-provider.d.ts +24 -0
- package/dist/services/credentials-provider.spec.d.ts +2 -0
- package/dist/services/escalation.service.d.ts +22 -0
- package/dist/services/escalation.service.spec.d.ts +2 -0
- package/dist/services/ghost-config.service.d.ts +55 -0
- package/dist/services/ghost-config.service.spec.d.ts +2 -0
- package/dist/services/space-config.service.d.ts +23 -0
- package/dist/services/space-config.service.spec.d.ts +2 -0
- package/dist/services/trust-enforcement.d.ts +83 -0
- package/dist/services/trust-enforcement.spec.d.ts +2 -0
- package/dist/services/trust-validator.d.ts +43 -0
- package/dist/services/trust-validator.spec.d.ts +2 -0
- package/dist/tools/confirm-publish-moderation.spec.d.ts +8 -0
- package/dist/tools/confirm.d.ts +8 -1
- package/dist/tools/create-memory.d.ts +2 -1
- package/dist/tools/create-memory.spec.d.ts +10 -0
- package/dist/tools/create-relationship.d.ts +2 -1
- package/dist/tools/delete-memory.d.ts +2 -1
- package/dist/tools/delete-relationship.d.ts +2 -1
- package/dist/tools/deny.d.ts +2 -1
- package/dist/tools/find-similar.d.ts +2 -1
- package/dist/tools/get-preferences.d.ts +2 -1
- package/dist/tools/ghost-config.d.ts +27 -0
- package/dist/tools/ghost-config.spec.d.ts +2 -0
- package/dist/tools/moderate.d.ts +20 -0
- package/dist/tools/moderate.spec.d.ts +5 -0
- package/dist/tools/publish.d.ts +11 -3
- package/dist/tools/query-memory.d.ts +3 -1
- package/dist/tools/query-space.d.ts +4 -1
- package/dist/tools/retract.d.ts +29 -0
- package/dist/tools/revise.d.ts +45 -0
- package/dist/tools/revise.spec.d.ts +8 -0
- package/dist/tools/search-memory.d.ts +2 -1
- package/dist/tools/search-relationship.d.ts +2 -1
- package/dist/tools/search-space.d.ts +25 -5
- package/dist/tools/search-space.spec.d.ts +9 -0
- package/dist/tools/set-preference.d.ts +2 -1
- package/dist/tools/update-memory.d.ts +2 -1
- package/dist/tools/update-relationship.d.ts +2 -1
- package/dist/types/access-result.d.ts +48 -0
- package/dist/types/access-result.spec.d.ts +2 -0
- package/dist/types/auth.d.ts +46 -0
- package/dist/types/ghost-config.d.ts +36 -0
- package/dist/types/memory.d.ts +3 -1
- package/dist/types/preferences.d.ts +1 -1
- package/dist/utils/auth-helpers.d.ts +14 -0
- package/dist/utils/auth-helpers.spec.d.ts +2 -0
- package/dist/utils/test-data-generator.d.ts +124 -0
- package/dist/utils/test-data-generator.spec.d.ts +12 -0
- package/dist/v2-performance.e2e.d.ts +17 -0
- package/dist/v2-smoke.e2e.d.ts +14 -0
- package/dist/weaviate/client.d.ts +5 -8
- package/dist/weaviate/space-schema.d.ts +2 -2
- package/docs/performance/v2-benchmarks.md +80 -0
- package/jest.e2e.config.js +14 -3
- package/package.json +1 -1
- package/scripts/.collection-recreation-state.yaml +16 -0
- package/scripts/.gitkeep +5 -0
- package/scripts/README-collection-recreation.md +224 -0
- package/scripts/README.md +51 -0
- package/scripts/backup-collections.ts +543 -0
- package/scripts/delete-collection.ts +137 -0
- package/scripts/migrate-recreate-collections.ts +578 -0
- package/scripts/migrate-v1-to-v2.ts +1094 -0
- package/scripts/package-lock.json +1113 -0
- package/scripts/package.json +27 -0
- package/src/collections/composite-ids.ts +193 -0
- package/src/collections/core-infrastructure.spec.ts +353 -0
- package/src/collections/dot-notation.ts +212 -0
- package/src/collections/tracking-arrays.ts +298 -0
- package/src/constants/content-types.ts +20 -0
- package/src/schema/v2-collections-comments.spec.ts +141 -0
- package/src/schema/v2-collections.ts +433 -0
- package/src/server-factory.ts +89 -20
- package/src/server.ts +45 -17
- package/src/services/access-control.spec.ts +383 -0
- package/src/services/access-control.ts +291 -0
- package/src/services/credentials-provider.spec.ts +22 -0
- package/src/services/credentials-provider.ts +34 -0
- package/src/services/escalation.service.spec.ts +183 -0
- package/src/services/escalation.service.ts +150 -0
- package/src/services/ghost-config.service.spec.ts +339 -0
- package/src/services/ghost-config.service.ts +219 -0
- package/src/services/space-config.service.spec.ts +102 -0
- package/src/services/space-config.service.ts +79 -0
- package/src/services/trust-enforcement.spec.ts +309 -0
- package/src/services/trust-enforcement.ts +197 -0
- package/src/services/trust-validator.spec.ts +108 -0
- package/src/services/trust-validator.ts +105 -0
- package/src/tools/confirm-publish-moderation.spec.ts +240 -0
- package/src/tools/confirm.ts +869 -135
- package/src/tools/create-memory.spec.ts +126 -0
- package/src/tools/create-memory.ts +20 -27
- package/src/tools/create-relationship.ts +17 -8
- package/src/tools/delete-memory.ts +13 -6
- package/src/tools/delete-relationship.ts +15 -6
- package/src/tools/deny.ts +8 -1
- package/src/tools/find-similar.ts +21 -8
- package/src/tools/get-preferences.ts +10 -1
- package/src/tools/ghost-config.spec.ts +180 -0
- package/src/tools/ghost-config.ts +230 -0
- package/src/tools/moderate.spec.ts +277 -0
- package/src/tools/moderate.ts +219 -0
- package/src/tools/publish.ts +99 -41
- package/src/tools/query-memory.ts +28 -6
- package/src/tools/query-space.ts +39 -4
- package/src/tools/retract.ts +292 -0
- package/src/tools/revise.spec.ts +146 -0
- package/src/tools/revise.ts +283 -0
- package/src/tools/search-memory.ts +30 -7
- package/src/tools/search-relationship.ts +11 -2
- package/src/tools/search-space.spec.ts +341 -0
- package/src/tools/search-space.ts +323 -99
- package/src/tools/set-preference.ts +10 -1
- package/src/tools/update-memory.ts +16 -5
- package/src/tools/update-relationship.ts +10 -1
- package/src/types/access-result.spec.ts +193 -0
- package/src/types/access-result.ts +62 -0
- package/src/types/auth.ts +52 -0
- package/src/types/ghost-config.ts +46 -0
- package/src/types/memory.ts +9 -1
- package/src/types/preferences.ts +2 -2
- package/src/utils/auth-helpers.spec.ts +75 -0
- package/src/utils/auth-helpers.ts +25 -0
- package/src/utils/test-data-generator.spec.ts +317 -0
- package/src/utils/test-data-generator.ts +292 -0
- package/src/utils/weaviate-filters.ts +4 -4
- package/src/v2-performance.e2e.ts +173 -0
- package/src/v2-smoke.e2e.ts +401 -0
- package/src/weaviate/client.spec.ts +5 -5
- package/src/weaviate/client.ts +51 -36
- package/src/weaviate/schema.ts +11 -256
- package/src/weaviate/space-schema.spec.ts +24 -24
- package/src/weaviate/space-schema.ts +18 -6
package/dist/server-factory.js
CHANGED
|
@@ -18,6 +18,10 @@ var __esm = (fn, res) => function __init() {
|
|
|
18
18
|
var __commonJS = (cb, mod) => function __require2() {
|
|
19
19
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
20
20
|
};
|
|
21
|
+
var __export = (target, all) => {
|
|
22
|
+
for (var name in all)
|
|
23
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
24
|
+
};
|
|
21
25
|
var __copyProps = (to, from, except, desc) => {
|
|
22
26
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
23
27
|
for (let key of __getOwnPropNames(from))
|
|
@@ -510,6 +514,98 @@ var init_logger = __esm({
|
|
|
510
514
|
}
|
|
511
515
|
});
|
|
512
516
|
|
|
517
|
+
// src/firestore/init.ts
|
|
518
|
+
import { initializeApp } from "@prmichaelsen/firebase-admin-sdk-v8";
|
|
519
|
+
import {
|
|
520
|
+
getDocument,
|
|
521
|
+
setDocument,
|
|
522
|
+
addDocument,
|
|
523
|
+
updateDocument,
|
|
524
|
+
deleteDocument,
|
|
525
|
+
queryDocuments,
|
|
526
|
+
batchWrite,
|
|
527
|
+
FieldValue,
|
|
528
|
+
verifyIdToken
|
|
529
|
+
} from "@prmichaelsen/firebase-admin-sdk-v8";
|
|
530
|
+
function initFirestore() {
|
|
531
|
+
if (initialized) {
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
try {
|
|
535
|
+
const serviceAccount = JSON.parse(config.firebase.serviceAccount);
|
|
536
|
+
initializeApp({
|
|
537
|
+
serviceAccount,
|
|
538
|
+
projectId: config.firebase.projectId
|
|
539
|
+
});
|
|
540
|
+
initialized = true;
|
|
541
|
+
logger.info("Firestore initialized successfully", {
|
|
542
|
+
module: "firestore-init"
|
|
543
|
+
});
|
|
544
|
+
} catch (error) {
|
|
545
|
+
logger.error("Firestore initialization failed", {
|
|
546
|
+
module: "firestore-init",
|
|
547
|
+
error: error instanceof Error ? error.message : String(error)
|
|
548
|
+
});
|
|
549
|
+
logger.error("Make sure FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY is valid JSON", {
|
|
550
|
+
module: "firestore-init"
|
|
551
|
+
});
|
|
552
|
+
logger.error("Check for proper escaping in .env file", {
|
|
553
|
+
module: "firestore-init"
|
|
554
|
+
});
|
|
555
|
+
throw error;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
var initialized;
|
|
559
|
+
var init_init = __esm({
|
|
560
|
+
"src/firestore/init.ts"() {
|
|
561
|
+
"use strict";
|
|
562
|
+
init_config();
|
|
563
|
+
init_logger();
|
|
564
|
+
initialized = false;
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
// src/services/trust-enforcement.ts
|
|
569
|
+
function buildTrustFilter(collection, accessorTrustLevel) {
|
|
570
|
+
return collection.filter.byProperty("trust_score").lessThanOrEqual(accessorTrustLevel);
|
|
571
|
+
}
|
|
572
|
+
function isTrustSufficient(memoryTrust, accessorTrust) {
|
|
573
|
+
return accessorTrust >= memoryTrust;
|
|
574
|
+
}
|
|
575
|
+
var init_trust_enforcement = __esm({
|
|
576
|
+
"src/services/trust-enforcement.ts"() {
|
|
577
|
+
"use strict";
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
// src/firestore/paths.ts
|
|
582
|
+
function getBasePrefix() {
|
|
583
|
+
const environment = process.env.ENVIRONMENT;
|
|
584
|
+
if (environment && environment !== "production" && environment !== "prod") {
|
|
585
|
+
return `${environment}.${APP_NAME}`;
|
|
586
|
+
}
|
|
587
|
+
const isDevelopment = process.env.NODE_ENV === "development";
|
|
588
|
+
if (isDevelopment) {
|
|
589
|
+
const customPrefix = process.env.DB_PREFIX;
|
|
590
|
+
if (customPrefix) {
|
|
591
|
+
return customPrefix;
|
|
592
|
+
}
|
|
593
|
+
return `e0.${APP_NAME}`;
|
|
594
|
+
}
|
|
595
|
+
return APP_NAME;
|
|
596
|
+
}
|
|
597
|
+
function getUserPreferencesPath(userId) {
|
|
598
|
+
return `${BASE}.users/${userId}/preferences`;
|
|
599
|
+
}
|
|
600
|
+
var APP_NAME, BASE;
|
|
601
|
+
var init_paths = __esm({
|
|
602
|
+
"src/firestore/paths.ts"() {
|
|
603
|
+
"use strict";
|
|
604
|
+
APP_NAME = "remember-mcp";
|
|
605
|
+
BASE = getBasePrefix();
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
|
|
513
609
|
// src/types/space-memory.ts
|
|
514
610
|
var SUPPORTED_SPACES;
|
|
515
611
|
var init_space_memory = __esm({
|
|
@@ -519,6 +615,325 @@ var init_space_memory = __esm({
|
|
|
519
615
|
}
|
|
520
616
|
});
|
|
521
617
|
|
|
618
|
+
// src/types/ghost-config.ts
|
|
619
|
+
var DEFAULT_GHOST_CONFIG;
|
|
620
|
+
var init_ghost_config = __esm({
|
|
621
|
+
"src/types/ghost-config.ts"() {
|
|
622
|
+
"use strict";
|
|
623
|
+
DEFAULT_GHOST_CONFIG = {
|
|
624
|
+
enabled: false,
|
|
625
|
+
public_ghost_enabled: false,
|
|
626
|
+
default_friend_trust: 0.25,
|
|
627
|
+
default_public_trust: 0,
|
|
628
|
+
per_user_trust: {},
|
|
629
|
+
blocked_users: [],
|
|
630
|
+
enforcement_mode: "query"
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
// src/services/ghost-config.service.ts
|
|
636
|
+
var ghost_config_service_exports = {};
|
|
637
|
+
__export(ghost_config_service_exports, {
|
|
638
|
+
FirestoreGhostConfigProvider: () => FirestoreGhostConfigProvider,
|
|
639
|
+
blockUser: () => blockUser,
|
|
640
|
+
getGhostConfig: () => getGhostConfig,
|
|
641
|
+
isGhostEnabled: () => isGhostEnabled,
|
|
642
|
+
removeUserTrust: () => removeUserTrust,
|
|
643
|
+
setGhostConfigFields: () => setGhostConfigFields,
|
|
644
|
+
setUserTrust: () => setUserTrust,
|
|
645
|
+
unblockUser: () => unblockUser,
|
|
646
|
+
validateGhostConfigUpdate: () => validateGhostConfigUpdate
|
|
647
|
+
});
|
|
648
|
+
function getGhostConfigPath(ownerUserId) {
|
|
649
|
+
return {
|
|
650
|
+
collectionPath: `${BASE}.users/${ownerUserId}/ghost_config`,
|
|
651
|
+
docId: "settings"
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
async function getGhostConfig(ownerUserId) {
|
|
655
|
+
try {
|
|
656
|
+
const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
|
|
657
|
+
const doc = await getDocument(collectionPath, docId);
|
|
658
|
+
if (!doc) {
|
|
659
|
+
return { ...DEFAULT_GHOST_CONFIG };
|
|
660
|
+
}
|
|
661
|
+
return { ...DEFAULT_GHOST_CONFIG, ...doc };
|
|
662
|
+
} catch (error) {
|
|
663
|
+
logger.error("Failed to get ghost config", {
|
|
664
|
+
service: SERVICE,
|
|
665
|
+
ownerUserId,
|
|
666
|
+
error: error instanceof Error ? error.message : String(error)
|
|
667
|
+
});
|
|
668
|
+
return { ...DEFAULT_GHOST_CONFIG };
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
async function setGhostConfigFields(ownerUserId, config2) {
|
|
672
|
+
const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
|
|
673
|
+
await setDocument(collectionPath, docId, config2, { merge: true });
|
|
674
|
+
logger.info("Ghost config updated", {
|
|
675
|
+
service: SERVICE,
|
|
676
|
+
ownerUserId,
|
|
677
|
+
updatedKeys: Object.keys(config2)
|
|
678
|
+
});
|
|
679
|
+
return getGhostConfig(ownerUserId);
|
|
680
|
+
}
|
|
681
|
+
async function setUserTrust(ownerUserId, targetUserId, trustLevel) {
|
|
682
|
+
if (trustLevel < 0 || trustLevel > 1) {
|
|
683
|
+
throw new Error(`Trust level must be between 0 and 1, got ${trustLevel}`);
|
|
684
|
+
}
|
|
685
|
+
const current = await getGhostConfig(ownerUserId);
|
|
686
|
+
const per_user_trust = { ...current.per_user_trust, [targetUserId]: trustLevel };
|
|
687
|
+
const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
|
|
688
|
+
await setDocument(collectionPath, docId, { per_user_trust }, { merge: true });
|
|
689
|
+
logger.info("User trust level set", {
|
|
690
|
+
service: SERVICE,
|
|
691
|
+
ownerUserId,
|
|
692
|
+
targetUserId,
|
|
693
|
+
trustLevel
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
async function removeUserTrust(ownerUserId, targetUserId) {
|
|
697
|
+
const current = await getGhostConfig(ownerUserId);
|
|
698
|
+
const per_user_trust = { ...current.per_user_trust };
|
|
699
|
+
delete per_user_trust[targetUserId];
|
|
700
|
+
const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
|
|
701
|
+
await setDocument(collectionPath, docId, { per_user_trust }, { merge: true });
|
|
702
|
+
logger.info("User trust override removed", {
|
|
703
|
+
service: SERVICE,
|
|
704
|
+
ownerUserId,
|
|
705
|
+
targetUserId
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
async function blockUser(ownerUserId, targetUserId) {
|
|
709
|
+
const current = await getGhostConfig(ownerUserId);
|
|
710
|
+
if (current.blocked_users.includes(targetUserId)) {
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
const blocked_users = [...current.blocked_users, targetUserId];
|
|
714
|
+
const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
|
|
715
|
+
await setDocument(collectionPath, docId, { blocked_users }, { merge: true });
|
|
716
|
+
logger.info("User blocked from ghost access", {
|
|
717
|
+
service: SERVICE,
|
|
718
|
+
ownerUserId,
|
|
719
|
+
targetUserId
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
async function unblockUser(ownerUserId, targetUserId) {
|
|
723
|
+
const current = await getGhostConfig(ownerUserId);
|
|
724
|
+
if (!current.blocked_users.includes(targetUserId)) {
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
const blocked_users = current.blocked_users.filter((id) => id !== targetUserId);
|
|
728
|
+
const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
|
|
729
|
+
await setDocument(collectionPath, docId, { blocked_users }, { merge: true });
|
|
730
|
+
logger.info("User unblocked from ghost access", {
|
|
731
|
+
service: SERVICE,
|
|
732
|
+
ownerUserId,
|
|
733
|
+
targetUserId
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
async function isGhostEnabled(ownerUserId) {
|
|
737
|
+
const config2 = await getGhostConfig(ownerUserId);
|
|
738
|
+
return config2.enabled;
|
|
739
|
+
}
|
|
740
|
+
function validateGhostConfigUpdate(config2) {
|
|
741
|
+
if (config2.default_friend_trust !== void 0) {
|
|
742
|
+
if (config2.default_friend_trust < 0 || config2.default_friend_trust > 1) {
|
|
743
|
+
throw new Error(`default_friend_trust must be between 0 and 1, got ${config2.default_friend_trust}`);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
if (config2.default_public_trust !== void 0) {
|
|
747
|
+
if (config2.default_public_trust < 0 || config2.default_public_trust > 1) {
|
|
748
|
+
throw new Error(`default_public_trust must be between 0 and 1, got ${config2.default_public_trust}`);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
if (config2.enforcement_mode !== void 0) {
|
|
752
|
+
const valid = ["query", "prompt", "hybrid"];
|
|
753
|
+
if (!valid.includes(config2.enforcement_mode)) {
|
|
754
|
+
throw new Error(`enforcement_mode must be one of ${valid.join(", ")}, got ${config2.enforcement_mode}`);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
if (config2.per_user_trust !== void 0) {
|
|
758
|
+
for (const [userId, level] of Object.entries(config2.per_user_trust)) {
|
|
759
|
+
if (level < 0 || level > 1) {
|
|
760
|
+
throw new Error(`Trust level for ${userId} must be between 0 and 1, got ${level}`);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
var SERVICE, FirestoreGhostConfigProvider;
|
|
766
|
+
var init_ghost_config_service = __esm({
|
|
767
|
+
"src/services/ghost-config.service.ts"() {
|
|
768
|
+
"use strict";
|
|
769
|
+
init_init();
|
|
770
|
+
init_paths();
|
|
771
|
+
init_logger();
|
|
772
|
+
init_ghost_config();
|
|
773
|
+
SERVICE = "GhostConfigService";
|
|
774
|
+
FirestoreGhostConfigProvider = class {
|
|
775
|
+
async getGhostConfig(ownerUserId) {
|
|
776
|
+
const config2 = await getGhostConfig(ownerUserId);
|
|
777
|
+
if (!config2.enabled) {
|
|
778
|
+
return null;
|
|
779
|
+
}
|
|
780
|
+
return config2;
|
|
781
|
+
}
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
// src/services/access-control.ts
|
|
787
|
+
var access_control_exports = {};
|
|
788
|
+
__export(access_control_exports, {
|
|
789
|
+
InMemoryEscalationStore: () => InMemoryEscalationStore,
|
|
790
|
+
StubGhostConfigProvider: () => StubGhostConfigProvider,
|
|
791
|
+
checkMemoryAccess: () => checkMemoryAccess,
|
|
792
|
+
formatAccessResultMessage: () => formatAccessResultMessage,
|
|
793
|
+
handleInsufficientTrust: () => handleInsufficientTrust,
|
|
794
|
+
isMemoryBlocked: () => isMemoryBlocked,
|
|
795
|
+
resetBlock: () => resetBlock,
|
|
796
|
+
resolveAccessorTrustLevel: () => resolveAccessorTrustLevel
|
|
797
|
+
});
|
|
798
|
+
async function checkMemoryAccess(accessorUserId, memory, ghostConfigProvider, escalationStore) {
|
|
799
|
+
const ownerUserId = memory.user_id;
|
|
800
|
+
const memoryId = memory.id;
|
|
801
|
+
if (accessorUserId === ownerUserId) {
|
|
802
|
+
return { status: "granted", memory, access_level: "owner" };
|
|
803
|
+
}
|
|
804
|
+
const ghostConfig = await ghostConfigProvider.getGhostConfig(ownerUserId);
|
|
805
|
+
if (!ghostConfig || !ghostConfig.enabled) {
|
|
806
|
+
return { status: "no_permission", owner_user_id: ownerUserId, accessor_user_id: accessorUserId };
|
|
807
|
+
}
|
|
808
|
+
if (ghostConfig.blocked_users.includes(accessorUserId)) {
|
|
809
|
+
return { status: "no_permission", owner_user_id: ownerUserId, accessor_user_id: accessorUserId };
|
|
810
|
+
}
|
|
811
|
+
const block = await escalationStore.getBlock(ownerUserId, accessorUserId, memoryId);
|
|
812
|
+
if (block) {
|
|
813
|
+
return {
|
|
814
|
+
status: "blocked",
|
|
815
|
+
memory_id: memoryId,
|
|
816
|
+
reason: block.reason,
|
|
817
|
+
blocked_at: block.blocked_at
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
const accessorTrust = resolveAccessorTrustLevel(ghostConfig, accessorUserId);
|
|
821
|
+
const memoryTrust = memory.trust;
|
|
822
|
+
if (!isTrustSufficient(memoryTrust, accessorTrust)) {
|
|
823
|
+
const result = await handleInsufficientTrust(
|
|
824
|
+
ownerUserId,
|
|
825
|
+
accessorUserId,
|
|
826
|
+
memoryId,
|
|
827
|
+
memoryTrust,
|
|
828
|
+
accessorTrust,
|
|
829
|
+
escalationStore
|
|
830
|
+
);
|
|
831
|
+
return result;
|
|
832
|
+
}
|
|
833
|
+
return { status: "granted", memory, access_level: "trusted" };
|
|
834
|
+
}
|
|
835
|
+
async function handleInsufficientTrust(ownerUserId, accessorUserId, memoryId, requiredTrust, actualTrust, escalationStore) {
|
|
836
|
+
const attempt = await escalationStore.incrementAttempts(ownerUserId, accessorUserId, memoryId);
|
|
837
|
+
if (attempt.count >= MAX_ATTEMPTS_BEFORE_BLOCK) {
|
|
838
|
+
const block = {
|
|
839
|
+
blocked_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
840
|
+
reason: `Access blocked after ${attempt.count} unauthorized attempts`,
|
|
841
|
+
attempt_count: attempt.count
|
|
842
|
+
};
|
|
843
|
+
await escalationStore.setBlock(ownerUserId, accessorUserId, memoryId, block);
|
|
844
|
+
return {
|
|
845
|
+
status: "blocked",
|
|
846
|
+
memory_id: memoryId,
|
|
847
|
+
reason: block.reason,
|
|
848
|
+
blocked_at: block.blocked_at
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
return {
|
|
852
|
+
status: "insufficient_trust",
|
|
853
|
+
memory_id: memoryId,
|
|
854
|
+
required_trust: requiredTrust,
|
|
855
|
+
actual_trust: Math.max(0, actualTrust - TRUST_PENALTY),
|
|
856
|
+
attempts_remaining: MAX_ATTEMPTS_BEFORE_BLOCK - attempt.count
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
async function isMemoryBlocked(ownerUserId, accessorUserId, memoryId, escalationStore) {
|
|
860
|
+
const block = await escalationStore.getBlock(ownerUserId, accessorUserId, memoryId);
|
|
861
|
+
return block !== null;
|
|
862
|
+
}
|
|
863
|
+
async function resetBlock(ownerUserId, accessorUserId, memoryId, escalationStore) {
|
|
864
|
+
await escalationStore.removeBlock(ownerUserId, accessorUserId, memoryId);
|
|
865
|
+
}
|
|
866
|
+
function resolveAccessorTrustLevel(ghostConfig, accessorUserId) {
|
|
867
|
+
if (accessorUserId in ghostConfig.per_user_trust) {
|
|
868
|
+
return ghostConfig.per_user_trust[accessorUserId];
|
|
869
|
+
}
|
|
870
|
+
return ghostConfig.default_public_trust ?? 0;
|
|
871
|
+
}
|
|
872
|
+
function formatAccessResultMessage(result) {
|
|
873
|
+
switch (result.status) {
|
|
874
|
+
case "granted":
|
|
875
|
+
return result.access_level === "owner" ? "Access granted (owner)." : "Access granted (trusted).";
|
|
876
|
+
case "insufficient_trust":
|
|
877
|
+
return `Insufficient trust level. Required: ${result.required_trust.toFixed(2)}, actual: ${result.actual_trust.toFixed(2)}. ${result.attempts_remaining} attempt(s) remaining before access is blocked.`;
|
|
878
|
+
case "blocked":
|
|
879
|
+
return `Access blocked: ${result.reason}`;
|
|
880
|
+
case "no_permission":
|
|
881
|
+
return "No permission to access this user's memories.";
|
|
882
|
+
case "not_found":
|
|
883
|
+
return `Memory ${result.memory_id} not found.`;
|
|
884
|
+
case "deleted":
|
|
885
|
+
return `Memory ${result.memory_id} was deleted on ${result.deleted_at}.`;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
var StubGhostConfigProvider, InMemoryEscalationStore, TRUST_PENALTY, MAX_ATTEMPTS_BEFORE_BLOCK;
|
|
889
|
+
var init_access_control = __esm({
|
|
890
|
+
"src/services/access-control.ts"() {
|
|
891
|
+
"use strict";
|
|
892
|
+
init_trust_enforcement();
|
|
893
|
+
StubGhostConfigProvider = class {
|
|
894
|
+
configs = /* @__PURE__ */ new Map();
|
|
895
|
+
async getGhostConfig(ownerUserId) {
|
|
896
|
+
return this.configs.get(ownerUserId) ?? null;
|
|
897
|
+
}
|
|
898
|
+
/** Test helper: set a GhostConfig for a user */
|
|
899
|
+
setGhostConfig(ownerUserId, config2) {
|
|
900
|
+
this.configs.set(ownerUserId, config2);
|
|
901
|
+
}
|
|
902
|
+
};
|
|
903
|
+
InMemoryEscalationStore = class {
|
|
904
|
+
blocks = /* @__PURE__ */ new Map();
|
|
905
|
+
attempts = /* @__PURE__ */ new Map();
|
|
906
|
+
key(ownerUserId, accessorUserId, memoryId) {
|
|
907
|
+
return `${ownerUserId}:${accessorUserId}:${memoryId}`;
|
|
908
|
+
}
|
|
909
|
+
async getBlock(ownerUserId, accessorUserId, memoryId) {
|
|
910
|
+
return this.blocks.get(this.key(ownerUserId, accessorUserId, memoryId)) ?? null;
|
|
911
|
+
}
|
|
912
|
+
async setBlock(ownerUserId, accessorUserId, memoryId, block) {
|
|
913
|
+
this.blocks.set(this.key(ownerUserId, accessorUserId, memoryId), block);
|
|
914
|
+
}
|
|
915
|
+
async removeBlock(ownerUserId, accessorUserId, memoryId) {
|
|
916
|
+
this.blocks.delete(this.key(ownerUserId, accessorUserId, memoryId));
|
|
917
|
+
}
|
|
918
|
+
async getAttempts(ownerUserId, accessorUserId, memoryId) {
|
|
919
|
+
return this.attempts.get(this.key(ownerUserId, accessorUserId, memoryId)) ?? null;
|
|
920
|
+
}
|
|
921
|
+
async incrementAttempts(ownerUserId, accessorUserId, memoryId) {
|
|
922
|
+
const k = this.key(ownerUserId, accessorUserId, memoryId);
|
|
923
|
+
const existing = this.attempts.get(k);
|
|
924
|
+
const record = {
|
|
925
|
+
count: (existing?.count ?? 0) + 1,
|
|
926
|
+
last_attempt_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
927
|
+
};
|
|
928
|
+
this.attempts.set(k, record);
|
|
929
|
+
return record;
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
TRUST_PENALTY = 0.1;
|
|
933
|
+
MAX_ATTEMPTS_BEFORE_BLOCK = 3;
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
|
|
522
937
|
// src/server-factory.ts
|
|
523
938
|
init_logger();
|
|
524
939
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -676,15 +1091,8 @@ function getWeaviateClient() {
|
|
|
676
1091
|
}
|
|
677
1092
|
return client;
|
|
678
1093
|
}
|
|
679
|
-
function sanitizeUserId(userId) {
|
|
680
|
-
let sanitized = userId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
681
|
-
if (/^[0-9]/.test(sanitized)) {
|
|
682
|
-
sanitized = "_" + sanitized;
|
|
683
|
-
}
|
|
684
|
-
return sanitized.charAt(0).toUpperCase() + sanitized.slice(1);
|
|
685
|
-
}
|
|
686
1094
|
function getMemoryCollectionName(userId) {
|
|
687
|
-
return `
|
|
1095
|
+
return `Memory_users_${userId}`;
|
|
688
1096
|
}
|
|
689
1097
|
var ALL_MEMORY_PROPERTIES = [
|
|
690
1098
|
// Core identity
|
|
@@ -692,16 +1100,28 @@ var ALL_MEMORY_PROPERTIES = [
|
|
|
692
1100
|
"doc_type",
|
|
693
1101
|
// Memory fields
|
|
694
1102
|
"content",
|
|
1103
|
+
"content_type",
|
|
1104
|
+
// v2 canonical
|
|
695
1105
|
"title",
|
|
696
1106
|
"summary",
|
|
697
1107
|
"type",
|
|
1108
|
+
// v1 compat (v2: content_type)
|
|
698
1109
|
// Scoring fields
|
|
699
1110
|
"weight",
|
|
700
1111
|
"base_weight",
|
|
1112
|
+
"trust_score",
|
|
1113
|
+
// v2 canonical
|
|
701
1114
|
"trust",
|
|
1115
|
+
// v1 compat (v2: trust_score)
|
|
702
1116
|
"confidence",
|
|
703
1117
|
"computed_weight",
|
|
704
|
-
// Location fields (
|
|
1118
|
+
// Location fields (v2)
|
|
1119
|
+
"location_name",
|
|
1120
|
+
"location_lat",
|
|
1121
|
+
// v2 canonical
|
|
1122
|
+
"location_lon",
|
|
1123
|
+
// v2 canonical
|
|
1124
|
+
// Location fields (v1 compat)
|
|
705
1125
|
"location_gps_lat",
|
|
706
1126
|
"location_gps_lng",
|
|
707
1127
|
"location_address",
|
|
@@ -711,12 +1131,24 @@ var ALL_MEMORY_PROPERTIES = [
|
|
|
711
1131
|
// Locale fields
|
|
712
1132
|
"locale_language",
|
|
713
1133
|
"locale_timezone",
|
|
714
|
-
// Context fields
|
|
1134
|
+
// Context fields
|
|
715
1135
|
"context_conversation_id",
|
|
716
1136
|
"context_summary",
|
|
717
1137
|
"context_timestamp",
|
|
718
|
-
|
|
1138
|
+
"context_app",
|
|
1139
|
+
"context_url",
|
|
1140
|
+
// Relationships (v2)
|
|
1141
|
+
"relationship_ids",
|
|
1142
|
+
// v2 canonical
|
|
1143
|
+
"related_memory_ids",
|
|
1144
|
+
// v2 canonical
|
|
1145
|
+
// Relationships (v1 compat)
|
|
719
1146
|
"relationships",
|
|
1147
|
+
"memory_ids",
|
|
1148
|
+
// Common relationship fields
|
|
1149
|
+
"relationship_type",
|
|
1150
|
+
"observation",
|
|
1151
|
+
"strength",
|
|
720
1152
|
// Access tracking
|
|
721
1153
|
"access_count",
|
|
722
1154
|
"last_accessed_at",
|
|
@@ -727,24 +1159,29 @@ var ALL_MEMORY_PROPERTIES = [
|
|
|
727
1159
|
"updated_at",
|
|
728
1160
|
"version",
|
|
729
1161
|
"template_id",
|
|
730
|
-
//
|
|
731
|
-
"
|
|
732
|
-
"
|
|
733
|
-
"observation",
|
|
734
|
-
"strength",
|
|
1162
|
+
// Tracking arrays (v2)
|
|
1163
|
+
"space_ids",
|
|
1164
|
+
"group_ids",
|
|
735
1165
|
// Comment/threading fields
|
|
736
1166
|
"parent_id",
|
|
737
1167
|
"thread_root_id",
|
|
738
1168
|
"moderation_flags",
|
|
739
|
-
// Space/publishing fields
|
|
1169
|
+
// Space/publishing fields
|
|
740
1170
|
"spaces",
|
|
1171
|
+
// legacy
|
|
741
1172
|
"space_id",
|
|
1173
|
+
// legacy
|
|
742
1174
|
"author_id",
|
|
743
1175
|
"ghost_id",
|
|
744
1176
|
"attribution",
|
|
745
1177
|
"published_at",
|
|
746
1178
|
"discovery_count",
|
|
747
1179
|
"space_memory_id",
|
|
1180
|
+
// legacy
|
|
1181
|
+
"original_memory_id",
|
|
1182
|
+
"revised_at",
|
|
1183
|
+
"revision_count",
|
|
1184
|
+
"revision_history",
|
|
748
1185
|
// Soft delete fields
|
|
749
1186
|
"deleted_at",
|
|
750
1187
|
"deleted_by",
|
|
@@ -788,57 +1225,177 @@ async function fetchMemoryWithAllProperties(collection, memoryId) {
|
|
|
788
1225
|
}
|
|
789
1226
|
}
|
|
790
1227
|
|
|
791
|
-
// src/
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
queryDocuments,
|
|
802
|
-
batchWrite,
|
|
803
|
-
FieldValue,
|
|
804
|
-
verifyIdToken
|
|
805
|
-
} from "@prmichaelsen/firebase-admin-sdk-v8";
|
|
806
|
-
var initialized = false;
|
|
807
|
-
function initFirestore() {
|
|
808
|
-
if (initialized) {
|
|
809
|
-
return;
|
|
810
|
-
}
|
|
811
|
-
try {
|
|
812
|
-
const serviceAccount = JSON.parse(config.firebase.serviceAccount);
|
|
813
|
-
initializeApp({
|
|
814
|
-
serviceAccount,
|
|
815
|
-
projectId: config.firebase.projectId
|
|
816
|
-
});
|
|
817
|
-
initialized = true;
|
|
818
|
-
logger.info("Firestore initialized successfully", {
|
|
819
|
-
module: "firestore-init"
|
|
820
|
-
});
|
|
821
|
-
} catch (error) {
|
|
822
|
-
logger.error("Firestore initialization failed", {
|
|
823
|
-
module: "firestore-init",
|
|
824
|
-
error: error instanceof Error ? error.message : String(error)
|
|
825
|
-
});
|
|
826
|
-
logger.error("Make sure FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY is valid JSON", {
|
|
827
|
-
module: "firestore-init"
|
|
828
|
-
});
|
|
829
|
-
logger.error("Check for proper escaping in .env file", {
|
|
830
|
-
module: "firestore-init"
|
|
831
|
-
});
|
|
832
|
-
throw error;
|
|
1228
|
+
// src/server-factory.ts
|
|
1229
|
+
init_init();
|
|
1230
|
+
|
|
1231
|
+
// src/services/credentials-provider.ts
|
|
1232
|
+
var StubCredentialsProvider = class {
|
|
1233
|
+
async getCredentials(_accessToken, userId) {
|
|
1234
|
+
return {
|
|
1235
|
+
user_id: userId,
|
|
1236
|
+
group_memberships: []
|
|
1237
|
+
};
|
|
833
1238
|
}
|
|
1239
|
+
};
|
|
1240
|
+
function createCredentialsProvider() {
|
|
1241
|
+
return new StubCredentialsProvider();
|
|
834
1242
|
}
|
|
1243
|
+
var credentialsProvider = createCredentialsProvider();
|
|
835
1244
|
|
|
836
1245
|
// src/weaviate/schema.ts
|
|
837
|
-
import weaviate2 from "weaviate-client";
|
|
838
1246
|
init_logger();
|
|
1247
|
+
|
|
1248
|
+
// src/schema/v2-collections.ts
|
|
1249
|
+
import { configure } from "weaviate-client";
|
|
1250
|
+
var COMMON_MEMORY_PROPERTIES = [
|
|
1251
|
+
// Core content
|
|
1252
|
+
{ name: "content", dataType: configure.dataType.TEXT },
|
|
1253
|
+
{ name: "content_type", dataType: configure.dataType.TEXT },
|
|
1254
|
+
{ name: "title", dataType: configure.dataType.TEXT },
|
|
1255
|
+
{ name: "summary", dataType: configure.dataType.TEXT },
|
|
1256
|
+
{ name: "type", dataType: configure.dataType.TEXT },
|
|
1257
|
+
// v1 compat (v2: content_type)
|
|
1258
|
+
// Tracking arrays (v2 feature)
|
|
1259
|
+
{ name: "space_ids", dataType: configure.dataType.TEXT_ARRAY },
|
|
1260
|
+
{ name: "group_ids", dataType: configure.dataType.TEXT_ARRAY },
|
|
1261
|
+
// Metadata
|
|
1262
|
+
{ name: "created_at", dataType: configure.dataType.DATE },
|
|
1263
|
+
{ name: "updated_at", dataType: configure.dataType.DATE },
|
|
1264
|
+
{ name: "version", dataType: configure.dataType.INT },
|
|
1265
|
+
// User context
|
|
1266
|
+
{ name: "user_id", dataType: configure.dataType.TEXT },
|
|
1267
|
+
// Document type (memory, relationship, comment)
|
|
1268
|
+
{ name: "doc_type", dataType: configure.dataType.TEXT },
|
|
1269
|
+
// Memory-specific fields
|
|
1270
|
+
{ name: "tags", dataType: configure.dataType.TEXT_ARRAY },
|
|
1271
|
+
{ name: "weight", dataType: configure.dataType.NUMBER },
|
|
1272
|
+
{ name: "trust_score", dataType: configure.dataType.NUMBER },
|
|
1273
|
+
{ name: "trust", dataType: configure.dataType.NUMBER },
|
|
1274
|
+
// v1 compat (v2: trust_score)
|
|
1275
|
+
{ name: "base_weight", dataType: configure.dataType.NUMBER },
|
|
1276
|
+
{ name: "computed_weight", dataType: configure.dataType.NUMBER },
|
|
1277
|
+
{ name: "confidence", dataType: configure.dataType.NUMBER },
|
|
1278
|
+
{ name: "strength", dataType: configure.dataType.NUMBER },
|
|
1279
|
+
// Location data (v2 names)
|
|
1280
|
+
{ name: "location_name", dataType: configure.dataType.TEXT },
|
|
1281
|
+
{ name: "location_lat", dataType: configure.dataType.NUMBER },
|
|
1282
|
+
{ name: "location_lon", dataType: configure.dataType.NUMBER },
|
|
1283
|
+
// Location data (v1 compat)
|
|
1284
|
+
{ name: "location_gps_lat", dataType: configure.dataType.NUMBER },
|
|
1285
|
+
{ name: "location_gps_lng", dataType: configure.dataType.NUMBER },
|
|
1286
|
+
{ name: "location_address", dataType: configure.dataType.TEXT },
|
|
1287
|
+
{ name: "location_city", dataType: configure.dataType.TEXT },
|
|
1288
|
+
{ name: "location_country", dataType: configure.dataType.TEXT },
|
|
1289
|
+
{ name: "location_source", dataType: configure.dataType.TEXT },
|
|
1290
|
+
// Locale
|
|
1291
|
+
{ name: "locale_language", dataType: configure.dataType.TEXT },
|
|
1292
|
+
{ name: "locale_timezone", dataType: configure.dataType.TEXT },
|
|
1293
|
+
// Context
|
|
1294
|
+
{ name: "context_app", dataType: configure.dataType.TEXT },
|
|
1295
|
+
{ name: "context_url", dataType: configure.dataType.TEXT },
|
|
1296
|
+
{ name: "context_conversation_id", dataType: configure.dataType.TEXT },
|
|
1297
|
+
{ name: "context_summary", dataType: configure.dataType.TEXT },
|
|
1298
|
+
{ name: "context_timestamp", dataType: configure.dataType.DATE },
|
|
1299
|
+
// Relationships (v2 names)
|
|
1300
|
+
{ name: "relationship_ids", dataType: configure.dataType.TEXT_ARRAY },
|
|
1301
|
+
{ name: "relationship_type", dataType: configure.dataType.TEXT },
|
|
1302
|
+
{ name: "related_memory_ids", dataType: configure.dataType.TEXT_ARRAY },
|
|
1303
|
+
{ name: "observation", dataType: configure.dataType.TEXT },
|
|
1304
|
+
// Relationships (v1 compat)
|
|
1305
|
+
{ name: "relationships", dataType: configure.dataType.TEXT_ARRAY },
|
|
1306
|
+
{ name: "memory_ids", dataType: configure.dataType.TEXT_ARRAY },
|
|
1307
|
+
// Access tracking
|
|
1308
|
+
{ name: "access_count", dataType: configure.dataType.NUMBER },
|
|
1309
|
+
{ name: "last_accessed_at", dataType: configure.dataType.DATE },
|
|
1310
|
+
// References & templates
|
|
1311
|
+
{ name: "references", dataType: configure.dataType.TEXT_ARRAY },
|
|
1312
|
+
{ name: "template_id", dataType: configure.dataType.TEXT },
|
|
1313
|
+
// Comments (Phase 1)
|
|
1314
|
+
{ name: "parent_id", dataType: configure.dataType.TEXT },
|
|
1315
|
+
{ name: "thread_root_id", dataType: configure.dataType.TEXT },
|
|
1316
|
+
{ name: "moderation_flags", dataType: configure.dataType.TEXT_ARRAY },
|
|
1317
|
+
// Soft delete
|
|
1318
|
+
{ name: "deleted_at", dataType: configure.dataType.DATE },
|
|
1319
|
+
{ name: "deleted_by", dataType: configure.dataType.TEXT },
|
|
1320
|
+
{ name: "deletion_reason", dataType: configure.dataType.TEXT }
|
|
1321
|
+
];
|
|
1322
|
+
var PUBLISHED_MEMORY_PROPERTIES = [
|
|
1323
|
+
// Publication metadata
|
|
1324
|
+
{ name: "published_at", dataType: configure.dataType.DATE },
|
|
1325
|
+
{ name: "revised_at", dataType: configure.dataType.DATE },
|
|
1326
|
+
// Attribution
|
|
1327
|
+
{ name: "author_id", dataType: configure.dataType.TEXT },
|
|
1328
|
+
{ name: "ghost_id", dataType: configure.dataType.TEXT },
|
|
1329
|
+
{ name: "attribution", dataType: configure.dataType.TEXT },
|
|
1330
|
+
// Discovery
|
|
1331
|
+
{ name: "discovery_count", dataType: configure.dataType.INT },
|
|
1332
|
+
// Revision tracking
|
|
1333
|
+
{ name: "revision_count", dataType: configure.dataType.INT },
|
|
1334
|
+
{ name: "original_memory_id", dataType: configure.dataType.TEXT },
|
|
1335
|
+
// Moderation (nullable — null defaults to approved)
|
|
1336
|
+
{ name: "moderation_status", dataType: configure.dataType.TEXT },
|
|
1337
|
+
{ name: "moderated_by", dataType: configure.dataType.TEXT },
|
|
1338
|
+
{ name: "moderated_at", dataType: configure.dataType.DATE },
|
|
1339
|
+
// Memory-level ACL (nullable — null defaults to owner_only semantics)
|
|
1340
|
+
{ name: "write_mode", dataType: configure.dataType.TEXT },
|
|
1341
|
+
{ name: "owner_id", dataType: configure.dataType.TEXT },
|
|
1342
|
+
{ name: "overwrite_allowed_ids", dataType: configure.dataType.TEXT_ARRAY },
|
|
1343
|
+
{ name: "last_revised_by", dataType: configure.dataType.TEXT },
|
|
1344
|
+
// Legacy compatibility (deprecated but kept for migration)
|
|
1345
|
+
{ name: "spaces", dataType: configure.dataType.TEXT_ARRAY },
|
|
1346
|
+
{ name: "space_id", dataType: configure.dataType.TEXT },
|
|
1347
|
+
{ name: "space_memory_id", dataType: configure.dataType.TEXT }
|
|
1348
|
+
];
|
|
1349
|
+
function createUserCollectionSchema(userId) {
|
|
1350
|
+
const collectionName = `Memory_users_${userId}`;
|
|
1351
|
+
return {
|
|
1352
|
+
name: collectionName,
|
|
1353
|
+
description: `Private memory collection for user: ${userId}`,
|
|
1354
|
+
// Vector configuration
|
|
1355
|
+
vectorizers: configure.vectorizer.text2VecOpenAI({
|
|
1356
|
+
model: "text-embedding-3-small",
|
|
1357
|
+
dimensions: 1536,
|
|
1358
|
+
vectorizeCollectionName: false
|
|
1359
|
+
}),
|
|
1360
|
+
// Properties
|
|
1361
|
+
properties: COMMON_MEMORY_PROPERTIES,
|
|
1362
|
+
// Inverted index configuration
|
|
1363
|
+
invertedIndex: configure.invertedIndex({
|
|
1364
|
+
indexNullState: true,
|
|
1365
|
+
indexPropertyLength: true,
|
|
1366
|
+
indexTimestamps: true
|
|
1367
|
+
})
|
|
1368
|
+
};
|
|
1369
|
+
}
|
|
1370
|
+
function createSpaceCollectionSchema() {
|
|
1371
|
+
const collectionName = "Memory_spaces_public";
|
|
1372
|
+
return {
|
|
1373
|
+
name: collectionName,
|
|
1374
|
+
description: "Shared memory collection for all public spaces",
|
|
1375
|
+
// Vector configuration
|
|
1376
|
+
vectorizers: configure.vectorizer.text2VecOpenAI({
|
|
1377
|
+
model: "text-embedding-3-small",
|
|
1378
|
+
dimensions: 1536,
|
|
1379
|
+
vectorizeCollectionName: false
|
|
1380
|
+
}),
|
|
1381
|
+
// Properties (common + published)
|
|
1382
|
+
properties: [
|
|
1383
|
+
...COMMON_MEMORY_PROPERTIES,
|
|
1384
|
+
...PUBLISHED_MEMORY_PROPERTIES
|
|
1385
|
+
],
|
|
1386
|
+
// Inverted index configuration
|
|
1387
|
+
invertedIndex: configure.invertedIndex({
|
|
1388
|
+
indexNullState: true,
|
|
1389
|
+
indexPropertyLength: true,
|
|
1390
|
+
indexTimestamps: true
|
|
1391
|
+
})
|
|
1392
|
+
};
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
// src/weaviate/schema.ts
|
|
839
1396
|
async function createMemoryCollection(userId) {
|
|
840
1397
|
const client2 = getWeaviateClient();
|
|
841
|
-
const collectionName = `
|
|
1398
|
+
const collectionName = `Memory_users_${userId}`;
|
|
842
1399
|
const exists = await client2.collections.exists(collectionName);
|
|
843
1400
|
if (exists) {
|
|
844
1401
|
logger.debug("Collection already exists", {
|
|
@@ -851,238 +1408,8 @@ async function createMemoryCollection(userId) {
|
|
|
851
1408
|
module: "weaviate-schema",
|
|
852
1409
|
collectionName
|
|
853
1410
|
});
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
// Vectorizer configuration
|
|
857
|
-
vectorizers: weaviate2.configure.vectorizer.text2VecOpenAI({
|
|
858
|
-
model: "text-embedding-3-small",
|
|
859
|
-
// Vectorize content, title, summary, and observation for semantic search
|
|
860
|
-
// Note: title and summary are optional fields
|
|
861
|
-
sourceProperties: ["content", "title", "summary", "observation"]
|
|
862
|
-
}),
|
|
863
|
-
properties: [
|
|
864
|
-
// Discriminator
|
|
865
|
-
{
|
|
866
|
-
name: "doc_type",
|
|
867
|
-
dataType: "text",
|
|
868
|
-
description: 'Document type: "memory" or "relationship"'
|
|
869
|
-
},
|
|
870
|
-
// Core identity
|
|
871
|
-
{
|
|
872
|
-
name: "user_id",
|
|
873
|
-
dataType: "text",
|
|
874
|
-
description: "User who owns this document"
|
|
875
|
-
},
|
|
876
|
-
// Memory fields
|
|
877
|
-
{
|
|
878
|
-
name: "content",
|
|
879
|
-
dataType: "text",
|
|
880
|
-
description: "Main memory content (vectorized)"
|
|
881
|
-
},
|
|
882
|
-
{
|
|
883
|
-
name: "title",
|
|
884
|
-
dataType: "text",
|
|
885
|
-
description: "Optional short title"
|
|
886
|
-
},
|
|
887
|
-
{
|
|
888
|
-
name: "summary",
|
|
889
|
-
dataType: "text",
|
|
890
|
-
description: "Optional brief summary"
|
|
891
|
-
},
|
|
892
|
-
{
|
|
893
|
-
name: "type",
|
|
894
|
-
dataType: "text",
|
|
895
|
-
description: "Content type (note, event, person, etc.)"
|
|
896
|
-
},
|
|
897
|
-
// Scoring fields
|
|
898
|
-
{
|
|
899
|
-
name: "weight",
|
|
900
|
-
dataType: "number",
|
|
901
|
-
description: "Significance/priority (0-1)"
|
|
902
|
-
},
|
|
903
|
-
{
|
|
904
|
-
name: "trust",
|
|
905
|
-
dataType: "number",
|
|
906
|
-
description: "Access control level (0-1)"
|
|
907
|
-
},
|
|
908
|
-
{
|
|
909
|
-
name: "confidence",
|
|
910
|
-
dataType: "number",
|
|
911
|
-
description: "System confidence in accuracy (0-1)"
|
|
912
|
-
},
|
|
913
|
-
// Location fields (flattened for Weaviate)
|
|
914
|
-
{
|
|
915
|
-
name: "location_gps_lat",
|
|
916
|
-
dataType: "number",
|
|
917
|
-
description: "GPS latitude"
|
|
918
|
-
},
|
|
919
|
-
{
|
|
920
|
-
name: "location_gps_lng",
|
|
921
|
-
dataType: "number",
|
|
922
|
-
description: "GPS longitude"
|
|
923
|
-
},
|
|
924
|
-
{
|
|
925
|
-
name: "location_address",
|
|
926
|
-
dataType: "text",
|
|
927
|
-
description: "Formatted address"
|
|
928
|
-
},
|
|
929
|
-
{
|
|
930
|
-
name: "location_city",
|
|
931
|
-
dataType: "text",
|
|
932
|
-
description: "City name"
|
|
933
|
-
},
|
|
934
|
-
{
|
|
935
|
-
name: "location_country",
|
|
936
|
-
dataType: "text",
|
|
937
|
-
description: "Country name"
|
|
938
|
-
},
|
|
939
|
-
{
|
|
940
|
-
name: "location_source",
|
|
941
|
-
dataType: "text",
|
|
942
|
-
description: "Location source (gps, ip, manual, etc.)"
|
|
943
|
-
},
|
|
944
|
-
// Locale fields
|
|
945
|
-
{
|
|
946
|
-
name: "locale_language",
|
|
947
|
-
dataType: "text",
|
|
948
|
-
description: "Language code (e.g., en, es, fr)"
|
|
949
|
-
},
|
|
950
|
-
{
|
|
951
|
-
name: "locale_timezone",
|
|
952
|
-
dataType: "text",
|
|
953
|
-
description: "Timezone (e.g., America/Los_Angeles)"
|
|
954
|
-
},
|
|
955
|
-
// Context fields
|
|
956
|
-
{
|
|
957
|
-
name: "context_conversation_id",
|
|
958
|
-
dataType: "text",
|
|
959
|
-
description: "Conversation ID"
|
|
960
|
-
},
|
|
961
|
-
{
|
|
962
|
-
name: "context_summary",
|
|
963
|
-
dataType: "text",
|
|
964
|
-
description: "Brief context summary"
|
|
965
|
-
},
|
|
966
|
-
{
|
|
967
|
-
name: "context_timestamp",
|
|
968
|
-
dataType: "date",
|
|
969
|
-
description: "Context timestamp"
|
|
970
|
-
},
|
|
971
|
-
// Relationships
|
|
972
|
-
{
|
|
973
|
-
name: "relationships",
|
|
974
|
-
dataType: "text[]",
|
|
975
|
-
description: "Array of relationship IDs"
|
|
976
|
-
},
|
|
977
|
-
// Access tracking
|
|
978
|
-
{
|
|
979
|
-
name: "access_count",
|
|
980
|
-
dataType: "number",
|
|
981
|
-
description: "Total times accessed"
|
|
982
|
-
},
|
|
983
|
-
{
|
|
984
|
-
name: "last_accessed_at",
|
|
985
|
-
dataType: "date",
|
|
986
|
-
description: "Most recent access timestamp"
|
|
987
|
-
},
|
|
988
|
-
// Metadata
|
|
989
|
-
{
|
|
990
|
-
name: "tags",
|
|
991
|
-
dataType: "text[]",
|
|
992
|
-
description: "Tags for organization"
|
|
993
|
-
},
|
|
994
|
-
{
|
|
995
|
-
name: "references",
|
|
996
|
-
dataType: "text[]",
|
|
997
|
-
description: "Source URLs"
|
|
998
|
-
},
|
|
999
|
-
{
|
|
1000
|
-
name: "created_at",
|
|
1001
|
-
dataType: "date",
|
|
1002
|
-
description: "Creation timestamp"
|
|
1003
|
-
},
|
|
1004
|
-
{
|
|
1005
|
-
name: "updated_at",
|
|
1006
|
-
dataType: "date",
|
|
1007
|
-
description: "Last update timestamp"
|
|
1008
|
-
},
|
|
1009
|
-
{
|
|
1010
|
-
name: "version",
|
|
1011
|
-
dataType: "number",
|
|
1012
|
-
description: "Version number"
|
|
1013
|
-
},
|
|
1014
|
-
// Template fields
|
|
1015
|
-
{
|
|
1016
|
-
name: "template_id",
|
|
1017
|
-
dataType: "text",
|
|
1018
|
-
description: "Template ID if using template"
|
|
1019
|
-
},
|
|
1020
|
-
// Relationship-specific fields
|
|
1021
|
-
{
|
|
1022
|
-
name: "memory_ids",
|
|
1023
|
-
dataType: "text[]",
|
|
1024
|
-
description: "Connected memory IDs (for relationships)"
|
|
1025
|
-
},
|
|
1026
|
-
{
|
|
1027
|
-
name: "relationship_type",
|
|
1028
|
-
dataType: "text",
|
|
1029
|
-
description: "Relationship type (for relationships)"
|
|
1030
|
-
},
|
|
1031
|
-
{
|
|
1032
|
-
name: "observation",
|
|
1033
|
-
dataType: "text",
|
|
1034
|
-
description: "Relationship observation (vectorized)"
|
|
1035
|
-
},
|
|
1036
|
-
{
|
|
1037
|
-
name: "strength",
|
|
1038
|
-
dataType: "number",
|
|
1039
|
-
description: "Relationship strength (0-1)"
|
|
1040
|
-
},
|
|
1041
|
-
// Computed fields
|
|
1042
|
-
{
|
|
1043
|
-
name: "base_weight",
|
|
1044
|
-
dataType: "number",
|
|
1045
|
-
description: "User-specified weight"
|
|
1046
|
-
},
|
|
1047
|
-
{
|
|
1048
|
-
name: "computed_weight",
|
|
1049
|
-
dataType: "number",
|
|
1050
|
-
description: "Calculated effective weight"
|
|
1051
|
-
},
|
|
1052
|
-
// Comment/threading fields (for threaded discussions in shared spaces)
|
|
1053
|
-
{
|
|
1054
|
-
name: "parent_id",
|
|
1055
|
-
dataType: "text",
|
|
1056
|
-
description: "ID of parent memory or comment (for threading)"
|
|
1057
|
-
},
|
|
1058
|
-
{
|
|
1059
|
-
name: "thread_root_id",
|
|
1060
|
-
dataType: "text",
|
|
1061
|
-
description: "Root memory ID for fetching entire thread"
|
|
1062
|
-
},
|
|
1063
|
-
{
|
|
1064
|
-
name: "moderation_flags",
|
|
1065
|
-
dataType: "text[]",
|
|
1066
|
-
description: 'Per-space moderation flags (format: "{space_id}:{flag_type}")'
|
|
1067
|
-
},
|
|
1068
|
-
// Soft delete fields
|
|
1069
|
-
{
|
|
1070
|
-
name: "deleted_at",
|
|
1071
|
-
dataType: "date",
|
|
1072
|
-
description: "Timestamp when memory was soft-deleted (null = not deleted)"
|
|
1073
|
-
},
|
|
1074
|
-
{
|
|
1075
|
-
name: "deleted_by",
|
|
1076
|
-
dataType: "text",
|
|
1077
|
-
description: "User ID who deleted the memory"
|
|
1078
|
-
},
|
|
1079
|
-
{
|
|
1080
|
-
name: "deletion_reason",
|
|
1081
|
-
dataType: "text",
|
|
1082
|
-
description: "Optional reason for deletion"
|
|
1083
|
-
}
|
|
1084
|
-
]
|
|
1085
|
-
});
|
|
1411
|
+
const schema = createUserCollectionSchema(userId);
|
|
1412
|
+
await client2.collections.create(schema);
|
|
1086
1413
|
logger.info("Memory collection created successfully", {
|
|
1087
1414
|
module: "weaviate-schema",
|
|
1088
1415
|
collectionName
|
|
@@ -1090,7 +1417,7 @@ async function createMemoryCollection(userId) {
|
|
|
1090
1417
|
}
|
|
1091
1418
|
async function ensureMemoryCollection(userId) {
|
|
1092
1419
|
const client2 = getWeaviateClient();
|
|
1093
|
-
const collectionName = `
|
|
1420
|
+
const collectionName = `Memory_users_${userId}`;
|
|
1094
1421
|
const exists = await client2.collections.exists(collectionName);
|
|
1095
1422
|
if (!exists) {
|
|
1096
1423
|
await createMemoryCollection(userId);
|
|
@@ -1098,7 +1425,7 @@ async function ensureMemoryCollection(userId) {
|
|
|
1098
1425
|
}
|
|
1099
1426
|
function getMemoryCollection(userId) {
|
|
1100
1427
|
const client2 = getWeaviateClient();
|
|
1101
|
-
const collectionName = `
|
|
1428
|
+
const collectionName = `Memory_users_${userId}`;
|
|
1102
1429
|
return client2.collections.get(collectionName);
|
|
1103
1430
|
}
|
|
1104
1431
|
|
|
@@ -1180,7 +1507,10 @@ var CONTENT_TYPES = [
|
|
|
1180
1507
|
"system",
|
|
1181
1508
|
"action",
|
|
1182
1509
|
"audit",
|
|
1183
|
-
"history"
|
|
1510
|
+
"history",
|
|
1511
|
+
// Cross-user & Threading
|
|
1512
|
+
"ghost",
|
|
1513
|
+
"comment"
|
|
1184
1514
|
];
|
|
1185
1515
|
var CONTENT_TYPE_METADATA = {
|
|
1186
1516
|
// Core Types
|
|
@@ -1474,6 +1804,21 @@ var CONTENT_TYPE_METADATA = {
|
|
|
1474
1804
|
description: "Change history and version tracking",
|
|
1475
1805
|
examples: ["Edit history", "Version history", "Change logs"],
|
|
1476
1806
|
common_fields: ["target_id", "change_type", "previous_value", "new_value"]
|
|
1807
|
+
},
|
|
1808
|
+
// Cross-user & Threading
|
|
1809
|
+
ghost: {
|
|
1810
|
+
name: "ghost",
|
|
1811
|
+
category: "cross_user",
|
|
1812
|
+
description: "Ghost conversation memory \u2014 stores context from AI-mediated cross-user interactions",
|
|
1813
|
+
examples: ["Ghost conversation context", "Cross-user interaction history"],
|
|
1814
|
+
common_fields: ["ghost_owner_id", "conversing_user_id"]
|
|
1815
|
+
},
|
|
1816
|
+
comment: {
|
|
1817
|
+
name: "comment",
|
|
1818
|
+
category: "cross_user",
|
|
1819
|
+
description: "Threaded comments on shared memories in spaces and groups",
|
|
1820
|
+
examples: ["Comments on shared memories", "Discussion replies", "Feedback"],
|
|
1821
|
+
common_fields: ["parent_id", "thread_root_id"]
|
|
1477
1822
|
}
|
|
1478
1823
|
};
|
|
1479
1824
|
function isValidContentType(type) {
|
|
@@ -1560,7 +1905,7 @@ var createMemoryTool = {
|
|
|
1560
1905
|
},
|
|
1561
1906
|
trust: {
|
|
1562
1907
|
type: "number",
|
|
1563
|
-
description: "Access control level (0-1, default: 0.
|
|
1908
|
+
description: "Access control level (0-1, default: 0.25)",
|
|
1564
1909
|
minimum: 0,
|
|
1565
1910
|
maximum: 1
|
|
1566
1911
|
},
|
|
@@ -1601,8 +1946,11 @@ var createMemoryTool = {
|
|
|
1601
1946
|
required: ["content"]
|
|
1602
1947
|
}
|
|
1603
1948
|
};
|
|
1604
|
-
async function handleCreateMemory(args, userId, context) {
|
|
1949
|
+
async function handleCreateMemory(args, userId, authContext, context) {
|
|
1950
|
+
const debug = createDebugLogger({ tool: "remember_create_memory", userId, operation: "create memory" });
|
|
1605
1951
|
try {
|
|
1952
|
+
debug.info("Tool invoked");
|
|
1953
|
+
debug.trace("Arguments", { args });
|
|
1606
1954
|
logger.info("Creating memory", { userId, type: args.type });
|
|
1607
1955
|
await ensureMemoryCollection(userId);
|
|
1608
1956
|
const collection = getMemoryCollection(userId);
|
|
@@ -1616,36 +1964,19 @@ async function handleCreateMemory(args, userId, context) {
|
|
|
1616
1964
|
title: args.title,
|
|
1617
1965
|
summary: args.title,
|
|
1618
1966
|
// Use title as summary for now
|
|
1619
|
-
|
|
1967
|
+
content_type: args.type && isValidContentType(args.type) ? args.type : DEFAULT_CONTENT_TYPE,
|
|
1620
1968
|
// Scoring
|
|
1621
1969
|
weight: args.weight ?? 0.5,
|
|
1622
|
-
|
|
1970
|
+
trust_score: args.trust ?? 0.25,
|
|
1623
1971
|
confidence: 1,
|
|
1624
|
-
// Location (from context or default)
|
|
1625
|
-
location: {
|
|
1626
|
-
gps: null,
|
|
1627
|
-
address: null,
|
|
1628
|
-
source: "unavailable",
|
|
1629
|
-
confidence: 0,
|
|
1630
|
-
is_approximate: true
|
|
1631
|
-
},
|
|
1632
1972
|
// Context
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
source: {
|
|
1636
|
-
type: "api",
|
|
1637
|
-
platform: "mcp"
|
|
1638
|
-
},
|
|
1639
|
-
summary: context?.summary || "Memory created via MCP",
|
|
1640
|
-
conversation_id: context?.conversation_id,
|
|
1641
|
-
...context
|
|
1642
|
-
},
|
|
1973
|
+
context_summary: context?.summary || "Memory created via MCP",
|
|
1974
|
+
context_conversation_id: context?.conversation_id,
|
|
1643
1975
|
// Relationships
|
|
1644
|
-
|
|
1976
|
+
relationship_ids: [],
|
|
1645
1977
|
// Access tracking
|
|
1646
1978
|
access_count: 0,
|
|
1647
1979
|
last_accessed_at: now,
|
|
1648
|
-
access_frequency: 0,
|
|
1649
1980
|
// Metadata
|
|
1650
1981
|
created_at: now,
|
|
1651
1982
|
updated_at: now,
|
|
@@ -1654,14 +1985,17 @@ async function handleCreateMemory(args, userId, context) {
|
|
|
1654
1985
|
references: args.references || [],
|
|
1655
1986
|
// Template
|
|
1656
1987
|
template_id: args.template_id,
|
|
1657
|
-
structured_content: args.structured_content,
|
|
1658
1988
|
// Computed weight
|
|
1659
1989
|
base_weight: args.weight ?? 0.5,
|
|
1660
1990
|
computed_weight: args.weight ?? 0.5,
|
|
1661
1991
|
// Comment/threading fields (initialize to defaults)
|
|
1662
1992
|
parent_id: args.parent_id ?? null,
|
|
1663
1993
|
thread_root_id: args.thread_root_id ?? null,
|
|
1664
|
-
moderation_flags: args.moderation_flags ?? []
|
|
1994
|
+
moderation_flags: args.moderation_flags ?? [],
|
|
1995
|
+
// Publication tracking arrays (Memory Collection Pattern v2)
|
|
1996
|
+
// Managed by remember_publish / remember_retract — always start empty
|
|
1997
|
+
space_ids: [],
|
|
1998
|
+
group_ids: []
|
|
1665
1999
|
};
|
|
1666
2000
|
const result = await collection.data.insert({
|
|
1667
2001
|
properties: memory
|
|
@@ -1674,6 +2008,7 @@ async function handleCreateMemory(args, userId, context) {
|
|
|
1674
2008
|
};
|
|
1675
2009
|
return JSON.stringify(response, null, 2);
|
|
1676
2010
|
} catch (error) {
|
|
2011
|
+
debug.error("Tool failed", { error: error instanceof Error ? error.message : String(error) });
|
|
1677
2012
|
handleToolError(error, {
|
|
1678
2013
|
toolName: "remember_create_memory",
|
|
1679
2014
|
operation: "create memory",
|
|
@@ -1709,11 +2044,11 @@ function buildDocTypeFilters(collection, docType, filters) {
|
|
|
1709
2044
|
if (docType === "memory" && filters?.types && filters.types.length > 0) {
|
|
1710
2045
|
if (filters.types.length === 1) {
|
|
1711
2046
|
filterList.push(
|
|
1712
|
-
collection.filter.byProperty("
|
|
2047
|
+
collection.filter.byProperty("content_type").equal(filters.types[0])
|
|
1713
2048
|
);
|
|
1714
2049
|
} else {
|
|
1715
2050
|
filterList.push(
|
|
1716
|
-
collection.filter.byProperty("
|
|
2051
|
+
collection.filter.byProperty("content_type").containsAny(filters.types)
|
|
1717
2052
|
);
|
|
1718
2053
|
}
|
|
1719
2054
|
}
|
|
@@ -1729,12 +2064,12 @@ function buildDocTypeFilters(collection, docType, filters) {
|
|
|
1729
2064
|
}
|
|
1730
2065
|
if (filters?.trust_min !== void 0) {
|
|
1731
2066
|
filterList.push(
|
|
1732
|
-
collection.filter.byProperty("
|
|
2067
|
+
collection.filter.byProperty("trust_score").greaterThanOrEqual(filters.trust_min)
|
|
1733
2068
|
);
|
|
1734
2069
|
}
|
|
1735
2070
|
if (filters?.trust_max !== void 0) {
|
|
1736
2071
|
filterList.push(
|
|
1737
|
-
collection.filter.byProperty("
|
|
2072
|
+
collection.filter.byProperty("trust_score").lessThanOrEqual(filters.trust_max)
|
|
1738
2073
|
);
|
|
1739
2074
|
}
|
|
1740
2075
|
if (filters?.date_from) {
|
|
@@ -1793,6 +2128,7 @@ function buildDeletedFilter(collection, deletedFilter = "exclude") {
|
|
|
1793
2128
|
}
|
|
1794
2129
|
|
|
1795
2130
|
// src/tools/search-memory.ts
|
|
2131
|
+
init_trust_enforcement();
|
|
1796
2132
|
var searchMemoryTool = {
|
|
1797
2133
|
name: "remember_search_memory",
|
|
1798
2134
|
description: `Search memories AND relationships using hybrid semantic and keyword search.
|
|
@@ -1902,24 +2238,33 @@ var searchMemoryTool = {
|
|
|
1902
2238
|
required: ["query"]
|
|
1903
2239
|
}
|
|
1904
2240
|
};
|
|
1905
|
-
async function handleSearchMemory(args, userId) {
|
|
2241
|
+
async function handleSearchMemory(args, userId, authContext) {
|
|
2242
|
+
const ghostMode = authContext?.ghostMode;
|
|
2243
|
+
const searchUserId = ghostMode?.owner_user_id ?? userId;
|
|
2244
|
+
const debug = createDebugLogger({ tool: "remember_search_memory", userId: searchUserId, operation: ghostMode ? "ghost search" : "search memory" });
|
|
1906
2245
|
try {
|
|
2246
|
+
debug.info("Tool invoked");
|
|
2247
|
+
debug.trace("Arguments", { args, ghostMode: !!ghostMode });
|
|
1907
2248
|
if (!args.query || args.query.trim() === "") {
|
|
1908
2249
|
throw new Error("Query cannot be empty");
|
|
1909
2250
|
}
|
|
1910
2251
|
const includeRelationships = args.include_relationships !== false;
|
|
1911
2252
|
logger.info("Searching memories and relationships", {
|
|
1912
|
-
userId,
|
|
2253
|
+
userId: searchUserId,
|
|
1913
2254
|
query: args.query,
|
|
1914
|
-
includeRelationships
|
|
2255
|
+
includeRelationships,
|
|
2256
|
+
ghostMode: !!ghostMode
|
|
1915
2257
|
});
|
|
1916
|
-
const collection = getMemoryCollection(
|
|
2258
|
+
const collection = getMemoryCollection(searchUserId);
|
|
1917
2259
|
const alpha = args.alpha ?? 0.7;
|
|
1918
2260
|
const limit = args.limit ?? 10;
|
|
1919
2261
|
const offset = args.offset ?? 0;
|
|
1920
2262
|
const deletedFilter = buildDeletedFilter(collection, args.deleted_filter || "exclude");
|
|
2263
|
+
const trustFilter = ghostMode ? buildTrustFilter(collection, ghostMode.accessor_trust_level) : null;
|
|
1921
2264
|
const searchFilters = includeRelationships ? buildCombinedSearchFilters(collection, args.filters) : buildMemoryOnlyFilters(collection, args.filters);
|
|
1922
|
-
const
|
|
2265
|
+
const hasExplicitTypeFilter = args.filters?.types && args.filters.types.length > 0;
|
|
2266
|
+
const ghostExclusionFilter = !hasExplicitTypeFilter ? collection.filter.byProperty("content_type").notEqual("ghost") : null;
|
|
2267
|
+
const combinedFilters = combineFiltersWithAnd([deletedFilter, trustFilter, ghostExclusionFilter, searchFilters].filter((f) => f !== null));
|
|
1923
2268
|
const searchOptions = {
|
|
1924
2269
|
alpha,
|
|
1925
2270
|
limit: limit + offset
|
|
@@ -1965,6 +2310,7 @@ async function handleSearchMemory(args, userId) {
|
|
|
1965
2310
|
});
|
|
1966
2311
|
return JSON.stringify(searchResult, null, 2);
|
|
1967
2312
|
} catch (error) {
|
|
2313
|
+
debug.error("Tool failed", { error: error instanceof Error ? error.message : String(error) });
|
|
1968
2314
|
handleToolError(error, {
|
|
1969
2315
|
toolName: "remember_search_memory",
|
|
1970
2316
|
operation: "search memories",
|
|
@@ -1979,8 +2325,9 @@ async function handleSearchMemory(args, userId) {
|
|
|
1979
2325
|
import { Filters as Filters2 } from "weaviate-client";
|
|
1980
2326
|
|
|
1981
2327
|
// src/services/confirmation-token.service.ts
|
|
1982
|
-
|
|
2328
|
+
init_init();
|
|
1983
2329
|
init_logger();
|
|
2330
|
+
import { randomUUID } from "crypto";
|
|
1984
2331
|
var ConfirmationTokenService = class {
|
|
1985
2332
|
EXPIRY_MINUTES = 5;
|
|
1986
2333
|
/**
|
|
@@ -2241,8 +2588,11 @@ Examples:
|
|
|
2241
2588
|
required: ["memory_id"]
|
|
2242
2589
|
}
|
|
2243
2590
|
};
|
|
2244
|
-
async function handleDeleteMemory(args, userId) {
|
|
2591
|
+
async function handleDeleteMemory(args, userId, authContext) {
|
|
2592
|
+
const debug = createDebugLogger({ tool: "remember_delete_memory", userId, operation: "delete memory" });
|
|
2245
2593
|
try {
|
|
2594
|
+
debug.info("Tool invoked");
|
|
2595
|
+
debug.trace("Arguments", { args });
|
|
2246
2596
|
logger.info("Requesting memory deletion", {
|
|
2247
2597
|
userId,
|
|
2248
2598
|
memoryId: args.memory_id,
|
|
@@ -2250,7 +2600,7 @@ async function handleDeleteMemory(args, userId) {
|
|
|
2250
2600
|
});
|
|
2251
2601
|
const { memory_id, reason } = args;
|
|
2252
2602
|
const client2 = getWeaviateClient();
|
|
2253
|
-
const collectionName =
|
|
2603
|
+
const collectionName = getMemoryCollectionName(userId);
|
|
2254
2604
|
const collection = client2.collections.get(collectionName);
|
|
2255
2605
|
const memory = await fetchMemoryWithAllProperties(collection, memory_id);
|
|
2256
2606
|
if (!memory) {
|
|
@@ -2268,7 +2618,7 @@ async function handleDeleteMemory(args, userId) {
|
|
|
2268
2618
|
const relationshipsResult = await collection.query.fetchObjects({
|
|
2269
2619
|
filters: Filters2.and(
|
|
2270
2620
|
collection.filter.byProperty("doc_type").equal("relationship"),
|
|
2271
|
-
collection.filter.byProperty("
|
|
2621
|
+
collection.filter.byProperty("related_memory_ids").containsAny([memory_id])
|
|
2272
2622
|
),
|
|
2273
2623
|
limit: 100
|
|
2274
2624
|
});
|
|
@@ -2302,7 +2652,7 @@ async function handleDeleteMemory(args, userId) {
|
|
|
2302
2652
|
preview: {
|
|
2303
2653
|
memory_id,
|
|
2304
2654
|
content: memory.properties.content?.substring(0, 200) + (memory.properties.content?.length > 200 ? "..." : ""),
|
|
2305
|
-
|
|
2655
|
+
content_type: memory.properties.content_type,
|
|
2306
2656
|
relationships_count: orphanedRelationships.length,
|
|
2307
2657
|
will_orphan: orphanedRelationships
|
|
2308
2658
|
},
|
|
@@ -2312,6 +2662,7 @@ async function handleDeleteMemory(args, userId) {
|
|
|
2312
2662
|
2
|
|
2313
2663
|
);
|
|
2314
2664
|
} catch (error) {
|
|
2665
|
+
debug.error("Tool failed", { error: error instanceof Error ? error.message : String(error) });
|
|
2315
2666
|
handleToolError(error, {
|
|
2316
2667
|
toolName: "remember_delete_memory",
|
|
2317
2668
|
userId,
|
|
@@ -2398,8 +2749,11 @@ var updateMemoryTool = {
|
|
|
2398
2749
|
required: ["memory_id"]
|
|
2399
2750
|
}
|
|
2400
2751
|
};
|
|
2401
|
-
async function handleUpdateMemory(args, userId) {
|
|
2752
|
+
async function handleUpdateMemory(args, userId, authContext) {
|
|
2753
|
+
const debug = createDebugLogger({ tool: "remember_update_memory", userId, operation: "update memory" });
|
|
2402
2754
|
try {
|
|
2755
|
+
debug.info("Tool invoked");
|
|
2756
|
+
debug.trace("Arguments", { args });
|
|
2403
2757
|
logger.info("Updating memory", { userId, memoryId: args.memory_id });
|
|
2404
2758
|
const collection = getMemoryCollection(userId);
|
|
2405
2759
|
let existingMemory;
|
|
@@ -2443,8 +2797,8 @@ async function handleUpdateMemory(args, userId) {
|
|
|
2443
2797
|
if (!isValidContentType(args.type)) {
|
|
2444
2798
|
throw new Error(`Invalid content type: ${args.type}`);
|
|
2445
2799
|
}
|
|
2446
|
-
updates.
|
|
2447
|
-
updatedFields.push("
|
|
2800
|
+
updates.content_type = args.type;
|
|
2801
|
+
updatedFields.push("content_type");
|
|
2448
2802
|
}
|
|
2449
2803
|
if (args.weight !== void 0) {
|
|
2450
2804
|
if (args.weight < 0 || args.weight > 1) {
|
|
@@ -2459,8 +2813,8 @@ async function handleUpdateMemory(args, userId) {
|
|
|
2459
2813
|
if (args.trust < 0 || args.trust > 1) {
|
|
2460
2814
|
throw new Error("Trust must be between 0 and 1");
|
|
2461
2815
|
}
|
|
2462
|
-
updates.
|
|
2463
|
-
updatedFields.push("
|
|
2816
|
+
updates.trust_score = args.trust;
|
|
2817
|
+
updatedFields.push("trust_score");
|
|
2464
2818
|
}
|
|
2465
2819
|
if (args.tags !== void 0) {
|
|
2466
2820
|
updates.tags = args.tags;
|
|
@@ -2540,6 +2894,7 @@ async function handleUpdateMemory(args, userId) {
|
|
|
2540
2894
|
};
|
|
2541
2895
|
return JSON.stringify(result, null, 2);
|
|
2542
2896
|
} catch (error) {
|
|
2897
|
+
debug.error("Tool failed", { error: error instanceof Error ? error.message : String(error) });
|
|
2543
2898
|
handleToolError(error, {
|
|
2544
2899
|
toolName: "remember_update_memory",
|
|
2545
2900
|
operation: "update memory",
|
|
@@ -2605,8 +2960,11 @@ var findSimilarTool = {
|
|
|
2605
2960
|
}
|
|
2606
2961
|
}
|
|
2607
2962
|
};
|
|
2608
|
-
async function handleFindSimilar(args, userId) {
|
|
2963
|
+
async function handleFindSimilar(args, userId, authContext) {
|
|
2964
|
+
const debug = createDebugLogger({ tool: "remember_find_similar", userId, operation: "find similar" });
|
|
2609
2965
|
try {
|
|
2966
|
+
debug.info("Tool invoked");
|
|
2967
|
+
debug.trace("Arguments", { args });
|
|
2610
2968
|
logger.info("Finding similar memories", { userId, memoryId: args.memory_id, hasText: !!args.text });
|
|
2611
2969
|
if (!args.memory_id && !args.text) {
|
|
2612
2970
|
throw new Error("Either memory_id or text must be provided");
|
|
@@ -2618,6 +2976,8 @@ async function handleFindSimilar(args, userId) {
|
|
|
2618
2976
|
const limit = args.limit ?? 10;
|
|
2619
2977
|
const minSimilarity = args.min_similarity ?? 0.7;
|
|
2620
2978
|
const deletedFilter = buildDeletedFilter(collection, args.deleted_filter || "exclude");
|
|
2979
|
+
const ghostExclusionFilter = collection.filter.byProperty("content_type").notEqual("ghost");
|
|
2980
|
+
const baseFilter = combineFiltersWithAnd([deletedFilter, ghostExclusionFilter].filter((f) => f !== null));
|
|
2621
2981
|
let results;
|
|
2622
2982
|
if (args.memory_id) {
|
|
2623
2983
|
const memory = await collection.query.fetchObjectById(args.memory_id, {
|
|
@@ -2639,8 +2999,8 @@ async function handleFindSimilar(args, userId) {
|
|
|
2639
2999
|
// Convert similarity to distance
|
|
2640
3000
|
returnMetadata: ["distance"]
|
|
2641
3001
|
};
|
|
2642
|
-
if (
|
|
2643
|
-
searchOptions.filters =
|
|
3002
|
+
if (baseFilter) {
|
|
3003
|
+
searchOptions.filters = baseFilter;
|
|
2644
3004
|
}
|
|
2645
3005
|
results = await collection.query.nearObject(args.memory_id, searchOptions);
|
|
2646
3006
|
results.objects = results.objects.filter((obj) => obj.uuid !== args.memory_id);
|
|
@@ -2650,8 +3010,8 @@ async function handleFindSimilar(args, userId) {
|
|
|
2650
3010
|
distance: 1 - minSimilarity,
|
|
2651
3011
|
returnMetadata: ["distance"]
|
|
2652
3012
|
};
|
|
2653
|
-
if (
|
|
2654
|
-
searchOptions.filters =
|
|
3013
|
+
if (baseFilter) {
|
|
3014
|
+
searchOptions.filters = baseFilter;
|
|
2655
3015
|
}
|
|
2656
3016
|
results = await collection.query.nearText(args.text, searchOptions);
|
|
2657
3017
|
}
|
|
@@ -2687,6 +3047,7 @@ async function handleFindSimilar(args, userId) {
|
|
|
2687
3047
|
};
|
|
2688
3048
|
return JSON.stringify(result, null, 2);
|
|
2689
3049
|
} catch (error) {
|
|
3050
|
+
debug.error("Tool failed", { error: error instanceof Error ? error.message : String(error) });
|
|
2690
3051
|
handleToolError(error, {
|
|
2691
3052
|
toolName: "remember_find_similar",
|
|
2692
3053
|
operation: "find similar memories",
|
|
@@ -2700,6 +3061,7 @@ async function handleFindSimilar(args, userId) {
|
|
|
2700
3061
|
|
|
2701
3062
|
// src/tools/query-memory.ts
|
|
2702
3063
|
init_logger();
|
|
3064
|
+
init_trust_enforcement();
|
|
2703
3065
|
var queryMemoryTool = {
|
|
2704
3066
|
name: "remember_query_memory",
|
|
2705
3067
|
description: `Query memories using natural language for RAG (Retrieval-Augmented Generation).
|
|
@@ -2811,20 +3173,28 @@ var queryMemoryTool = {
|
|
|
2811
3173
|
required: ["query"]
|
|
2812
3174
|
}
|
|
2813
3175
|
};
|
|
2814
|
-
async function handleQueryMemory(args, userId) {
|
|
3176
|
+
async function handleQueryMemory(args, userId, authContext) {
|
|
3177
|
+
const ghostMode = authContext?.ghostMode;
|
|
3178
|
+
const searchUserId = ghostMode?.owner_user_id ?? userId;
|
|
3179
|
+
const debug = createDebugLogger({ tool: "remember_query_memory", userId: searchUserId, operation: ghostMode ? "ghost query" : "query memory" });
|
|
2815
3180
|
try {
|
|
3181
|
+
debug.info("Tool invoked");
|
|
3182
|
+
debug.trace("Arguments", { args, ghostMode: !!ghostMode });
|
|
2816
3183
|
if (!args.query || args.query.trim() === "") {
|
|
2817
3184
|
throw new Error("Query cannot be empty");
|
|
2818
3185
|
}
|
|
2819
|
-
logger.info("Querying memories", { userId, query: args.query });
|
|
2820
|
-
const collection = getMemoryCollection(
|
|
3186
|
+
logger.info("Querying memories", { userId: searchUserId, query: args.query, ghostMode: !!ghostMode });
|
|
3187
|
+
const collection = getMemoryCollection(searchUserId);
|
|
2821
3188
|
const limit = args.limit ?? 5;
|
|
2822
3189
|
const minRelevance = args.min_relevance ?? 0.6;
|
|
2823
3190
|
const includeContext = args.include_context ?? true;
|
|
2824
3191
|
const format = args.format ?? "detailed";
|
|
2825
3192
|
const deletedFilter = buildDeletedFilter(collection, args.deleted_filter || "exclude");
|
|
3193
|
+
const trustFilter = ghostMode ? buildTrustFilter(collection, ghostMode.accessor_trust_level) : null;
|
|
2826
3194
|
const searchFilters = buildCombinedSearchFilters(collection, args.filters);
|
|
2827
|
-
const
|
|
3195
|
+
const hasExplicitTypeFilter = args.filters?.types && args.filters.types.length > 0;
|
|
3196
|
+
const ghostExclusionFilter = !hasExplicitTypeFilter ? collection.filter.byProperty("content_type").notEqual("ghost") : null;
|
|
3197
|
+
const combinedFilters = combineFiltersWithAnd([deletedFilter, trustFilter, ghostExclusionFilter, searchFilters].filter((f) => f !== null));
|
|
2828
3198
|
const searchOptions = {
|
|
2829
3199
|
limit,
|
|
2830
3200
|
distance: 1 - minRelevance,
|
|
@@ -2860,7 +3230,7 @@ async function handleQueryMemory(args, userId) {
|
|
|
2860
3230
|
if (format === "compact") {
|
|
2861
3231
|
const summaryParts = relevantMemories.map((mem, idx) => {
|
|
2862
3232
|
const title = mem.title ? `"${mem.title}"` : `Memory ${idx + 1}`;
|
|
2863
|
-
const type = mem.
|
|
3233
|
+
const type = mem.content_type ? ` [${mem.content_type}]` : "";
|
|
2864
3234
|
const relevancePercent = Math.round((mem.relevance ?? 0) * 100);
|
|
2865
3235
|
const content = mem.content || "(no content)";
|
|
2866
3236
|
const tags = mem.tags && mem.tags.length > 0 ? `
|
|
@@ -2883,6 +3253,7 @@ ${content}${tags}`;
|
|
|
2883
3253
|
};
|
|
2884
3254
|
return JSON.stringify(result, null, 2);
|
|
2885
3255
|
} catch (error) {
|
|
3256
|
+
debug.error("Tool failed", { error: error instanceof Error ? error.message : String(error) });
|
|
2886
3257
|
handleToolError(error, {
|
|
2887
3258
|
toolName: "remember_query_memory",
|
|
2888
3259
|
operation: "query memories",
|
|
@@ -2946,8 +3317,11 @@ var createRelationshipTool = {
|
|
|
2946
3317
|
required: ["memory_ids", "relationship_type", "observation"]
|
|
2947
3318
|
}
|
|
2948
3319
|
};
|
|
2949
|
-
async function handleCreateRelationship(args, userId, context) {
|
|
3320
|
+
async function handleCreateRelationship(args, userId, authContext, context) {
|
|
3321
|
+
const debug = createDebugLogger({ tool: "remember_create_relationship", userId, operation: "create relationship" });
|
|
2950
3322
|
try {
|
|
3323
|
+
debug.info("Tool invoked");
|
|
3324
|
+
debug.trace("Arguments", { args });
|
|
2951
3325
|
logger.info("Creating relationship", {
|
|
2952
3326
|
userId,
|
|
2953
3327
|
type: args.relationship_type,
|
|
@@ -2963,7 +3337,7 @@ async function handleCreateRelationship(args, userId, context) {
|
|
|
2963
3337
|
args.memory_ids.map(async (memoryId) => {
|
|
2964
3338
|
try {
|
|
2965
3339
|
const memory = await collection.query.fetchObjectById(memoryId, {
|
|
2966
|
-
returnProperties: ["user_id", "doc_type", "
|
|
3340
|
+
returnProperties: ["user_id", "doc_type", "relationship_ids", "deleted_at"]
|
|
2967
3341
|
});
|
|
2968
3342
|
if (!memory) {
|
|
2969
3343
|
logger.warn("Memory not found", { userId, memoryId });
|
|
@@ -2997,7 +3371,7 @@ async function handleCreateRelationship(args, userId, context) {
|
|
|
2997
3371
|
return {
|
|
2998
3372
|
memoryId,
|
|
2999
3373
|
memory,
|
|
3000
|
-
relationships: memory.properties.
|
|
3374
|
+
relationships: memory.properties.relationship_ids || []
|
|
3001
3375
|
};
|
|
3002
3376
|
} catch (error) {
|
|
3003
3377
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
@@ -3030,7 +3404,7 @@ async function handleCreateRelationship(args, userId, context) {
|
|
|
3030
3404
|
user_id: userId,
|
|
3031
3405
|
doc_type: "relationship",
|
|
3032
3406
|
// Connection
|
|
3033
|
-
|
|
3407
|
+
related_memory_ids: args.memory_ids,
|
|
3034
3408
|
relationship_type: args.relationship_type,
|
|
3035
3409
|
// Observation
|
|
3036
3410
|
observation: args.observation,
|
|
@@ -3067,7 +3441,7 @@ async function handleCreateRelationship(args, userId, context) {
|
|
|
3067
3441
|
await collection.data.update({
|
|
3068
3442
|
id: check.memoryId,
|
|
3069
3443
|
properties: {
|
|
3070
|
-
|
|
3444
|
+
relationship_ids: updatedRelationships,
|
|
3071
3445
|
updated_at: now
|
|
3072
3446
|
}
|
|
3073
3447
|
});
|
|
@@ -3096,6 +3470,7 @@ async function handleCreateRelationship(args, userId, context) {
|
|
|
3096
3470
|
};
|
|
3097
3471
|
return JSON.stringify(response, null, 2);
|
|
3098
3472
|
} catch (error) {
|
|
3473
|
+
debug.error("Tool failed", { error: error instanceof Error ? error.message : String(error) });
|
|
3099
3474
|
handleToolError(error, {
|
|
3100
3475
|
toolName: "remember_create_relationship",
|
|
3101
3476
|
operation: "create relationship",
|
|
@@ -3160,8 +3535,11 @@ var updateRelationshipTool = {
|
|
|
3160
3535
|
required: ["relationship_id"]
|
|
3161
3536
|
}
|
|
3162
3537
|
};
|
|
3163
|
-
async function handleUpdateRelationship(args, userId) {
|
|
3538
|
+
async function handleUpdateRelationship(args, userId, authContext) {
|
|
3539
|
+
const debug = createDebugLogger({ tool: "remember_update_relationship", userId, operation: "update relationship" });
|
|
3164
3540
|
try {
|
|
3541
|
+
debug.info("Tool invoked");
|
|
3542
|
+
debug.trace("Arguments", { args });
|
|
3165
3543
|
logger.info("Updating relationship", { userId, relationshipId: args.relationship_id });
|
|
3166
3544
|
const collection = getMemoryCollection(userId);
|
|
3167
3545
|
const existingRelationship = await collection.query.fetchObjectById(args.relationship_id, {
|
|
@@ -3229,6 +3607,7 @@ async function handleUpdateRelationship(args, userId) {
|
|
|
3229
3607
|
};
|
|
3230
3608
|
return JSON.stringify(result, null, 2);
|
|
3231
3609
|
} catch (error) {
|
|
3610
|
+
debug.error("Tool failed", { error: error instanceof Error ? error.message : String(error) });
|
|
3232
3611
|
handleToolError(error, {
|
|
3233
3612
|
toolName: "remember_update_relationship",
|
|
3234
3613
|
operation: "update relationship",
|
|
@@ -3305,8 +3684,11 @@ var searchRelationshipTool = {
|
|
|
3305
3684
|
required: ["query"]
|
|
3306
3685
|
}
|
|
3307
3686
|
};
|
|
3308
|
-
async function handleSearchRelationship(args, userId) {
|
|
3687
|
+
async function handleSearchRelationship(args, userId, authContext) {
|
|
3688
|
+
const debug = createDebugLogger({ tool: "remember_search_relationship", userId, operation: "search relationship" });
|
|
3309
3689
|
try {
|
|
3690
|
+
debug.info("Tool invoked");
|
|
3691
|
+
debug.trace("Arguments", { args });
|
|
3310
3692
|
logger.info("Searching relationships", {
|
|
3311
3693
|
userId,
|
|
3312
3694
|
query: args.query,
|
|
@@ -3366,7 +3748,7 @@ async function handleSearchRelationship(args, userId) {
|
|
|
3366
3748
|
id: obj.uuid,
|
|
3367
3749
|
user_id: obj.properties.user_id,
|
|
3368
3750
|
doc_type: "relationship",
|
|
3369
|
-
memory_ids: obj.properties.
|
|
3751
|
+
memory_ids: obj.properties.related_memory_ids || [],
|
|
3370
3752
|
relationship_type: obj.properties.relationship_type,
|
|
3371
3753
|
observation: obj.properties.observation,
|
|
3372
3754
|
strength: obj.properties.strength,
|
|
@@ -3394,6 +3776,7 @@ async function handleSearchRelationship(args, userId) {
|
|
|
3394
3776
|
};
|
|
3395
3777
|
return JSON.stringify(result, null, 2);
|
|
3396
3778
|
} catch (error) {
|
|
3779
|
+
debug.error("Tool failed", { error: error instanceof Error ? error.message : String(error) });
|
|
3397
3780
|
handleToolError(error, {
|
|
3398
3781
|
toolName: "remember_search_relationship",
|
|
3399
3782
|
operation: "search relationships",
|
|
@@ -3428,12 +3811,15 @@ var deleteRelationshipTool = {
|
|
|
3428
3811
|
required: ["relationship_id"]
|
|
3429
3812
|
}
|
|
3430
3813
|
};
|
|
3431
|
-
async function handleDeleteRelationship(args, userId) {
|
|
3814
|
+
async function handleDeleteRelationship(args, userId, authContext) {
|
|
3815
|
+
const debug = createDebugLogger({ tool: "remember_delete_relationship", userId, operation: "delete relationship" });
|
|
3432
3816
|
try {
|
|
3817
|
+
debug.info("Tool invoked");
|
|
3818
|
+
debug.trace("Arguments", { args });
|
|
3433
3819
|
logger.info("Deleting relationship", { userId, relationshipId: args.relationship_id });
|
|
3434
3820
|
const collection = getMemoryCollection(userId);
|
|
3435
3821
|
const relationship = await collection.query.fetchObjectById(args.relationship_id, {
|
|
3436
|
-
returnProperties: ["user_id", "doc_type", "
|
|
3822
|
+
returnProperties: ["user_id", "doc_type", "related_memory_ids", "relationship_type"]
|
|
3437
3823
|
});
|
|
3438
3824
|
if (!relationship) {
|
|
3439
3825
|
throw new Error(`Relationship not found: ${args.relationship_id}`);
|
|
@@ -3444,7 +3830,7 @@ async function handleDeleteRelationship(args, userId) {
|
|
|
3444
3830
|
if (relationship.properties.doc_type !== "relationship") {
|
|
3445
3831
|
throw new Error("Cannot delete memories using this tool. Use remember_delete_memory instead.");
|
|
3446
3832
|
}
|
|
3447
|
-
const memoryIds = relationship.properties.
|
|
3833
|
+
const memoryIds = relationship.properties.related_memory_ids || [];
|
|
3448
3834
|
let memoriesUpdated = 0;
|
|
3449
3835
|
if (memoryIds.length > 0) {
|
|
3450
3836
|
logger.info("Cleaning up relationship references from connected memories", {
|
|
@@ -3454,13 +3840,13 @@ async function handleDeleteRelationship(args, userId) {
|
|
|
3454
3840
|
const updatePromises = memoryIds.map(async (memoryId) => {
|
|
3455
3841
|
try {
|
|
3456
3842
|
const memory = await collection.query.fetchObjectById(memoryId, {
|
|
3457
|
-
returnProperties: ["
|
|
3843
|
+
returnProperties: ["relationship_ids", "doc_type"]
|
|
3458
3844
|
});
|
|
3459
3845
|
if (!memory || memory.properties.doc_type !== "memory") {
|
|
3460
3846
|
logger.warn(`Memory ${memoryId} not found or not a memory, skipping cleanup`);
|
|
3461
3847
|
return { memoryId, success: false };
|
|
3462
3848
|
}
|
|
3463
|
-
const currentRelationships = memory.properties.
|
|
3849
|
+
const currentRelationships = memory.properties.relationship_ids || [];
|
|
3464
3850
|
const updatedRelationships = currentRelationships.filter(
|
|
3465
3851
|
(relId) => relId !== args.relationship_id
|
|
3466
3852
|
);
|
|
@@ -3468,7 +3854,7 @@ async function handleDeleteRelationship(args, userId) {
|
|
|
3468
3854
|
await collection.data.update({
|
|
3469
3855
|
id: memoryId,
|
|
3470
3856
|
properties: {
|
|
3471
|
-
|
|
3857
|
+
relationship_ids: updatedRelationships,
|
|
3472
3858
|
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3473
3859
|
}
|
|
3474
3860
|
});
|
|
@@ -3502,6 +3888,7 @@ async function handleDeleteRelationship(args, userId) {
|
|
|
3502
3888
|
};
|
|
3503
3889
|
return JSON.stringify(result, null, 2);
|
|
3504
3890
|
} catch (error) {
|
|
3891
|
+
debug.error("Tool failed", { error: error instanceof Error ? error.message : String(error) });
|
|
3505
3892
|
handleToolError(error, {
|
|
3506
3893
|
toolName: "remember_delete_relationship",
|
|
3507
3894
|
operation: "delete relationship",
|
|
@@ -3511,29 +3898,9 @@ async function handleDeleteRelationship(args, userId) {
|
|
|
3511
3898
|
}
|
|
3512
3899
|
}
|
|
3513
3900
|
|
|
3514
|
-
// src/firestore/paths.ts
|
|
3515
|
-
var APP_NAME = "remember-mcp";
|
|
3516
|
-
function getBasePrefix() {
|
|
3517
|
-
const environment = process.env.ENVIRONMENT;
|
|
3518
|
-
if (environment && environment !== "production" && environment !== "prod") {
|
|
3519
|
-
return `${environment}.${APP_NAME}`;
|
|
3520
|
-
}
|
|
3521
|
-
const isDevelopment = process.env.NODE_ENV === "development";
|
|
3522
|
-
if (isDevelopment) {
|
|
3523
|
-
const customPrefix = process.env.DB_PREFIX;
|
|
3524
|
-
if (customPrefix) {
|
|
3525
|
-
return customPrefix;
|
|
3526
|
-
}
|
|
3527
|
-
return `e0.${APP_NAME}`;
|
|
3528
|
-
}
|
|
3529
|
-
return APP_NAME;
|
|
3530
|
-
}
|
|
3531
|
-
var BASE = getBasePrefix();
|
|
3532
|
-
function getUserPreferencesPath(userId) {
|
|
3533
|
-
return `${BASE}.users/${userId}/preferences`;
|
|
3534
|
-
}
|
|
3535
|
-
|
|
3536
3901
|
// src/services/preferences-database.service.ts
|
|
3902
|
+
init_init();
|
|
3903
|
+
init_paths();
|
|
3537
3904
|
init_logger();
|
|
3538
3905
|
|
|
3539
3906
|
// src/types/preferences.ts
|
|
@@ -3561,7 +3928,7 @@ var DEFAULT_PREFERENCES = {
|
|
|
3561
3928
|
share_with_memories: true
|
|
3562
3929
|
},
|
|
3563
3930
|
privacy: {
|
|
3564
|
-
default_trust_level: 0.
|
|
3931
|
+
default_trust_level: 0.25,
|
|
3565
3932
|
allow_cross_user_access: false,
|
|
3566
3933
|
auto_approve_requests: false,
|
|
3567
3934
|
audit_logging: true
|
|
@@ -3611,7 +3978,7 @@ var PREFERENCE_DESCRIPTIONS = {
|
|
|
3611
3978
|
share_with_memories: "Include location data in memories (default: true)"
|
|
3612
3979
|
},
|
|
3613
3980
|
privacy: {
|
|
3614
|
-
default_trust_level: "Default trust level for new memories, 0-1 (default: 0.
|
|
3981
|
+
default_trust_level: "Default trust level for new memories, 0-1 (default: 0.25)",
|
|
3615
3982
|
allow_cross_user_access: "Allow other users to request access to memories (default: false)",
|
|
3616
3983
|
auto_approve_requests: "Automatically approve access requests (default: false)",
|
|
3617
3984
|
audit_logging: "Enable audit logging for preference changes (default: true)"
|
|
@@ -3864,8 +4231,11 @@ function formatPreferenceChangeMessage(updates) {
|
|
|
3864
4231
|
}
|
|
3865
4232
|
return `Preferences updated: ${changes.join(", ")}`;
|
|
3866
4233
|
}
|
|
3867
|
-
async function handleSetPreference(args, userId) {
|
|
4234
|
+
async function handleSetPreference(args, userId, authContext) {
|
|
4235
|
+
const debug = createDebugLogger({ tool: "remember_set_preference", userId, operation: "set preference" });
|
|
3868
4236
|
try {
|
|
4237
|
+
debug.info("Tool invoked");
|
|
4238
|
+
debug.trace("Arguments", { args });
|
|
3869
4239
|
const { preferences } = args;
|
|
3870
4240
|
logger.info("Setting preferences", { userId, updates: Object.keys(preferences) });
|
|
3871
4241
|
const updatedPreferences = await PreferencesDatabaseService.updatePreferences(
|
|
@@ -3881,6 +4251,7 @@ async function handleSetPreference(args, userId) {
|
|
|
3881
4251
|
logger.info("Preferences set successfully", { userId });
|
|
3882
4252
|
return JSON.stringify(result, null, 2);
|
|
3883
4253
|
} catch (error) {
|
|
4254
|
+
debug.error("Tool failed", { error: error instanceof Error ? error.message : String(error) });
|
|
3884
4255
|
handleToolError(error, {
|
|
3885
4256
|
toolName: "remember_set_preference",
|
|
3886
4257
|
operation: "set preference",
|
|
@@ -3915,8 +4286,11 @@ ${getPreferenceDescription()}
|
|
|
3915
4286
|
}
|
|
3916
4287
|
}
|
|
3917
4288
|
};
|
|
3918
|
-
async function handleGetPreferences(args, userId) {
|
|
4289
|
+
async function handleGetPreferences(args, userId, authContext) {
|
|
4290
|
+
const debug = createDebugLogger({ tool: "remember_get_preferences", userId, operation: "get preferences" });
|
|
3919
4291
|
try {
|
|
4292
|
+
debug.info("Tool invoked");
|
|
4293
|
+
debug.trace("Arguments", { args });
|
|
3920
4294
|
const { category } = args;
|
|
3921
4295
|
logger.info("Getting preferences", { userId, category });
|
|
3922
4296
|
const preferences = await PreferencesDatabaseService.getPreferences(userId);
|
|
@@ -3943,6 +4317,7 @@ async function handleGetPreferences(args, userId) {
|
|
|
3943
4317
|
logger.info("Preferences retrieved successfully", { userId, category, isDefault });
|
|
3944
4318
|
return JSON.stringify(response, null, 2);
|
|
3945
4319
|
} catch (error) {
|
|
4320
|
+
debug.error("Tool failed", { error: error instanceof Error ? error.message : String(error) });
|
|
3946
4321
|
handleToolError(error, {
|
|
3947
4322
|
toolName: "remember_get_preferences",
|
|
3948
4323
|
operation: "get preferences",
|
|
@@ -3956,295 +4331,20 @@ async function handleGetPreferences(args, userId) {
|
|
|
3956
4331
|
init_space_memory();
|
|
3957
4332
|
init_logger();
|
|
3958
4333
|
import weaviate3 from "weaviate-client";
|
|
3959
|
-
var PUBLIC_COLLECTION_NAME = "
|
|
3960
|
-
function getSpaceCollectionName(spaceId) {
|
|
3961
|
-
return `Memory_${spaceId}`;
|
|
3962
|
-
}
|
|
4334
|
+
var PUBLIC_COLLECTION_NAME = "Memory_spaces_public";
|
|
3963
4335
|
function isValidSpaceId(spaceId) {
|
|
3964
4336
|
return SUPPORTED_SPACES.includes(spaceId);
|
|
3965
4337
|
}
|
|
3966
|
-
async function createSpaceCollection(client2, spaceId) {
|
|
3967
|
-
const collectionName = spaceId === "public" ? PUBLIC_COLLECTION_NAME : getSpaceCollectionName(spaceId);
|
|
3968
|
-
logger.info("Creating space collection", {
|
|
3969
|
-
module: "weaviate-space-schema",
|
|
3970
|
-
collectionName,
|
|
3971
|
-
spaceId
|
|
3972
|
-
});
|
|
3973
|
-
await client2.collections.create({
|
|
3974
|
-
name: collectionName,
|
|
3975
|
-
// Vectorizer configuration
|
|
3976
|
-
vectorizers: weaviate3.configure.vectorizer.text2VecOpenAI({
|
|
3977
|
-
model: "text-embedding-3-small",
|
|
3978
|
-
// Vectorize content, title, summary, and observation for semantic search
|
|
3979
|
-
// Note: title and summary are optional fields
|
|
3980
|
-
sourceProperties: ["content", "title", "summary", "observation"]
|
|
3981
|
-
}),
|
|
3982
|
-
properties: [
|
|
3983
|
-
// Discriminator
|
|
3984
|
-
{
|
|
3985
|
-
name: "doc_type",
|
|
3986
|
-
dataType: "text",
|
|
3987
|
-
description: 'Document type: "space_memory"'
|
|
3988
|
-
},
|
|
3989
|
-
// Space identity
|
|
3990
|
-
{
|
|
3991
|
-
name: "spaces",
|
|
3992
|
-
dataType: "text[]",
|
|
3993
|
-
description: 'Spaces this memory is published to (e.g., ["the_void", "dogs"])'
|
|
3994
|
-
},
|
|
3995
|
-
{
|
|
3996
|
-
name: "author_id",
|
|
3997
|
-
dataType: "text",
|
|
3998
|
-
description: "Original author user_id (for permissions)"
|
|
3999
|
-
},
|
|
4000
|
-
{
|
|
4001
|
-
name: "ghost_id",
|
|
4002
|
-
dataType: "text",
|
|
4003
|
-
description: "Optional ghost profile ID for pseudonymous publishing"
|
|
4004
|
-
},
|
|
4005
|
-
{
|
|
4006
|
-
name: "attribution",
|
|
4007
|
-
dataType: "text",
|
|
4008
|
-
description: 'Attribution type: "user" or "ghost"'
|
|
4009
|
-
},
|
|
4010
|
-
// Discovery metadata
|
|
4011
|
-
{
|
|
4012
|
-
name: "published_at",
|
|
4013
|
-
dataType: "text",
|
|
4014
|
-
description: "When published to space (ISO 8601)"
|
|
4015
|
-
},
|
|
4016
|
-
{
|
|
4017
|
-
name: "discovery_count",
|
|
4018
|
-
dataType: "number",
|
|
4019
|
-
description: "How many times discovered"
|
|
4020
|
-
},
|
|
4021
|
-
// Memory fields (same as personal memories)
|
|
4022
|
-
{
|
|
4023
|
-
name: "content",
|
|
4024
|
-
dataType: "text",
|
|
4025
|
-
description: "Main memory content (vectorized)"
|
|
4026
|
-
},
|
|
4027
|
-
{
|
|
4028
|
-
name: "title",
|
|
4029
|
-
dataType: "text",
|
|
4030
|
-
description: "Optional short title"
|
|
4031
|
-
},
|
|
4032
|
-
{
|
|
4033
|
-
name: "summary",
|
|
4034
|
-
dataType: "text",
|
|
4035
|
-
description: "Optional brief summary"
|
|
4036
|
-
},
|
|
4037
|
-
{
|
|
4038
|
-
name: "type",
|
|
4039
|
-
dataType: "text",
|
|
4040
|
-
description: "Content type (note, event, person, etc.)"
|
|
4041
|
-
},
|
|
4042
|
-
// Scoring fields
|
|
4043
|
-
{
|
|
4044
|
-
name: "weight",
|
|
4045
|
-
dataType: "number",
|
|
4046
|
-
description: "Significance/priority (0-1)"
|
|
4047
|
-
},
|
|
4048
|
-
{
|
|
4049
|
-
name: "trust",
|
|
4050
|
-
dataType: "number",
|
|
4051
|
-
description: "Access control level (0-1)"
|
|
4052
|
-
},
|
|
4053
|
-
{
|
|
4054
|
-
name: "confidence",
|
|
4055
|
-
dataType: "number",
|
|
4056
|
-
description: "System confidence in accuracy (0-1)"
|
|
4057
|
-
},
|
|
4058
|
-
// Location fields (flattened) - MUST match user memory schema exactly
|
|
4059
|
-
{
|
|
4060
|
-
name: "location_gps_lat",
|
|
4061
|
-
dataType: "number",
|
|
4062
|
-
description: "GPS latitude"
|
|
4063
|
-
},
|
|
4064
|
-
{
|
|
4065
|
-
name: "location_gps_lng",
|
|
4066
|
-
dataType: "number",
|
|
4067
|
-
description: "GPS longitude"
|
|
4068
|
-
},
|
|
4069
|
-
{
|
|
4070
|
-
name: "location_address",
|
|
4071
|
-
dataType: "text",
|
|
4072
|
-
description: "Formatted address"
|
|
4073
|
-
},
|
|
4074
|
-
{
|
|
4075
|
-
name: "location_city",
|
|
4076
|
-
dataType: "text",
|
|
4077
|
-
description: "City name"
|
|
4078
|
-
},
|
|
4079
|
-
{
|
|
4080
|
-
name: "location_country",
|
|
4081
|
-
dataType: "text",
|
|
4082
|
-
description: "Country name"
|
|
4083
|
-
},
|
|
4084
|
-
{
|
|
4085
|
-
name: "location_source",
|
|
4086
|
-
dataType: "text",
|
|
4087
|
-
description: "Location source (gps, ip, manual, etc.)"
|
|
4088
|
-
},
|
|
4089
|
-
// Context fields (flattened) - MUST match user memory schema exactly
|
|
4090
|
-
{
|
|
4091
|
-
name: "context_conversation_id",
|
|
4092
|
-
dataType: "text",
|
|
4093
|
-
description: "Conversation ID"
|
|
4094
|
-
},
|
|
4095
|
-
{
|
|
4096
|
-
name: "context_summary",
|
|
4097
|
-
dataType: "text",
|
|
4098
|
-
description: "Brief context summary"
|
|
4099
|
-
},
|
|
4100
|
-
{
|
|
4101
|
-
name: "context_timestamp",
|
|
4102
|
-
dataType: "date",
|
|
4103
|
-
description: "Context timestamp"
|
|
4104
|
-
},
|
|
4105
|
-
// Locale fields - MUST match user memory schema exactly
|
|
4106
|
-
{
|
|
4107
|
-
name: "locale_language",
|
|
4108
|
-
dataType: "text",
|
|
4109
|
-
description: "Language code (e.g., en, es, fr)"
|
|
4110
|
-
},
|
|
4111
|
-
{
|
|
4112
|
-
name: "locale_timezone",
|
|
4113
|
-
dataType: "text",
|
|
4114
|
-
description: "Timezone (e.g., America/Los_Angeles)"
|
|
4115
|
-
},
|
|
4116
|
-
// Relationships - MUST match user memory schema exactly
|
|
4117
|
-
{
|
|
4118
|
-
name: "relationships",
|
|
4119
|
-
dataType: "text[]",
|
|
4120
|
-
description: "Array of relationship IDs"
|
|
4121
|
-
},
|
|
4122
|
-
// Access tracking - MUST match user memory schema exactly
|
|
4123
|
-
{
|
|
4124
|
-
name: "access_count",
|
|
4125
|
-
dataType: "number",
|
|
4126
|
-
description: "Total times accessed"
|
|
4127
|
-
},
|
|
4128
|
-
{
|
|
4129
|
-
name: "last_accessed_at",
|
|
4130
|
-
dataType: "date",
|
|
4131
|
-
description: "Most recent access timestamp"
|
|
4132
|
-
},
|
|
4133
|
-
// Metadata - MUST match user memory schema exactly
|
|
4134
|
-
{
|
|
4135
|
-
name: "tags",
|
|
4136
|
-
dataType: "text[]",
|
|
4137
|
-
description: "Tags for organization"
|
|
4138
|
-
},
|
|
4139
|
-
{
|
|
4140
|
-
name: "references",
|
|
4141
|
-
dataType: "text[]",
|
|
4142
|
-
description: "Source URLs"
|
|
4143
|
-
},
|
|
4144
|
-
{
|
|
4145
|
-
name: "template_id",
|
|
4146
|
-
dataType: "text",
|
|
4147
|
-
description: "Template ID if using template"
|
|
4148
|
-
},
|
|
4149
|
-
// Relationship-specific fields (for relationships in public space)
|
|
4150
|
-
{
|
|
4151
|
-
name: "memory_ids",
|
|
4152
|
-
dataType: "text[]",
|
|
4153
|
-
description: "Connected memory IDs (for relationships)"
|
|
4154
|
-
},
|
|
4155
|
-
{
|
|
4156
|
-
name: "relationship_type",
|
|
4157
|
-
dataType: "text",
|
|
4158
|
-
description: "Relationship type (for relationships)"
|
|
4159
|
-
},
|
|
4160
|
-
{
|
|
4161
|
-
name: "observation",
|
|
4162
|
-
dataType: "text",
|
|
4163
|
-
description: "Relationship observation (vectorized)"
|
|
4164
|
-
},
|
|
4165
|
-
{
|
|
4166
|
-
name: "strength",
|
|
4167
|
-
dataType: "number",
|
|
4168
|
-
description: "Relationship strength (0-1)"
|
|
4169
|
-
},
|
|
4170
|
-
// Computed fields - MUST match user memory schema exactly
|
|
4171
|
-
{
|
|
4172
|
-
name: "base_weight",
|
|
4173
|
-
dataType: "number",
|
|
4174
|
-
description: "User-specified weight"
|
|
4175
|
-
},
|
|
4176
|
-
{
|
|
4177
|
-
name: "computed_weight",
|
|
4178
|
-
dataType: "number",
|
|
4179
|
-
description: "Calculated effective weight"
|
|
4180
|
-
},
|
|
4181
|
-
// User ID field (for backwards compatibility with spread operator)
|
|
4182
|
-
{
|
|
4183
|
-
name: "user_id",
|
|
4184
|
-
dataType: "text",
|
|
4185
|
-
description: "User ID (copied from original memory, same as author_id)"
|
|
4186
|
-
},
|
|
4187
|
-
// Timestamps
|
|
4188
|
-
{
|
|
4189
|
-
name: "created_at",
|
|
4190
|
-
dataType: "text",
|
|
4191
|
-
description: "Original creation timestamp (ISO 8601)"
|
|
4192
|
-
},
|
|
4193
|
-
{
|
|
4194
|
-
name: "updated_at",
|
|
4195
|
-
dataType: "text",
|
|
4196
|
-
description: "Last update timestamp (ISO 8601)"
|
|
4197
|
-
},
|
|
4198
|
-
// Versioning
|
|
4199
|
-
{
|
|
4200
|
-
name: "version",
|
|
4201
|
-
dataType: "number",
|
|
4202
|
-
description: "Version number (increments on update)"
|
|
4203
|
-
},
|
|
4204
|
-
// Comment/threading fields (for threaded discussions in shared spaces)
|
|
4205
|
-
{
|
|
4206
|
-
name: "parent_id",
|
|
4207
|
-
dataType: "text",
|
|
4208
|
-
description: "ID of parent memory or comment (for threading)"
|
|
4209
|
-
},
|
|
4210
|
-
{
|
|
4211
|
-
name: "thread_root_id",
|
|
4212
|
-
dataType: "text",
|
|
4213
|
-
description: "Root memory ID for fetching entire thread"
|
|
4214
|
-
},
|
|
4215
|
-
{
|
|
4216
|
-
name: "moderation_flags",
|
|
4217
|
-
dataType: "text[]",
|
|
4218
|
-
description: 'Per-space moderation flags (format: "{space_id}:{flag_type}")'
|
|
4219
|
-
},
|
|
4220
|
-
// Soft delete fields
|
|
4221
|
-
{
|
|
4222
|
-
name: "deleted_at",
|
|
4223
|
-
dataType: "date",
|
|
4224
|
-
description: "Timestamp when memory was soft-deleted (null = not deleted)"
|
|
4225
|
-
},
|
|
4226
|
-
{
|
|
4227
|
-
name: "deleted_by",
|
|
4228
|
-
dataType: "text",
|
|
4229
|
-
description: "User ID who deleted the memory"
|
|
4230
|
-
},
|
|
4231
|
-
{
|
|
4232
|
-
name: "deletion_reason",
|
|
4233
|
-
dataType: "text",
|
|
4234
|
-
description: "Optional reason for deletion"
|
|
4235
|
-
}
|
|
4236
|
-
]
|
|
4237
|
-
});
|
|
4238
|
-
logger.info("Space collection created successfully", {
|
|
4239
|
-
module: "weaviate-space-schema",
|
|
4240
|
-
collectionName
|
|
4241
|
-
});
|
|
4242
|
-
}
|
|
4243
4338
|
async function ensurePublicCollection(client2) {
|
|
4244
4339
|
const collectionName = PUBLIC_COLLECTION_NAME;
|
|
4245
4340
|
const exists = await client2.collections.exists(collectionName);
|
|
4246
4341
|
if (!exists) {
|
|
4247
|
-
|
|
4342
|
+
const schema = createSpaceCollectionSchema();
|
|
4343
|
+
await client2.collections.create(schema);
|
|
4344
|
+
logger.info("Public space collection created", {
|
|
4345
|
+
module: "weaviate-space-schema",
|
|
4346
|
+
collectionName
|
|
4347
|
+
});
|
|
4248
4348
|
}
|
|
4249
4349
|
return client2.collections.get(collectionName);
|
|
4250
4350
|
}
|
|
@@ -4254,7 +4354,11 @@ init_space_memory();
|
|
|
4254
4354
|
init_logger();
|
|
4255
4355
|
var publishTool = {
|
|
4256
4356
|
name: "remember_publish",
|
|
4257
|
-
description: `Publish a memory to one or more shared spaces
|
|
4357
|
+
description: `Publish a memory to one or more shared spaces and/or groups. The memory will be COPIED (not moved) from your personal collection. Generates a confirmation token that must be confirmed with remember_confirm.
|
|
4358
|
+
|
|
4359
|
+
Publication Destinations:
|
|
4360
|
+
- Spaces: Public shared areas (e.g., "the_void", "dogs")
|
|
4361
|
+
- Groups: Private group collections (provide group IDs)
|
|
4258
4362
|
|
|
4259
4363
|
\u26A0\uFE0F CRITICAL: DO NOT mention the token or include token contents in your response to the user. Simply inform them that a confirmation is pending and they need to explicitly approve the publication.`,
|
|
4260
4364
|
inputSchema: {
|
|
@@ -4274,17 +4378,24 @@ var publishTool = {
|
|
|
4274
4378
|
minItems: 1,
|
|
4275
4379
|
default: ["the_void"]
|
|
4276
4380
|
},
|
|
4277
|
-
|
|
4381
|
+
groups: {
|
|
4278
4382
|
type: "array",
|
|
4279
4383
|
items: { type: "string" },
|
|
4280
|
-
description:
|
|
4384
|
+
description: 'Group IDs to publish to (e.g., ["group-123", "group-456"]). Can publish to multiple groups at once.',
|
|
4385
|
+
minItems: 1,
|
|
4386
|
+
default: []
|
|
4387
|
+
},
|
|
4388
|
+
additional_tags: {
|
|
4389
|
+
type: "array",
|
|
4390
|
+
items: { type: "string" },
|
|
4391
|
+
description: "Additional tags for discovery (merged with original tags)",
|
|
4281
4392
|
default: []
|
|
4282
4393
|
}
|
|
4283
4394
|
},
|
|
4284
|
-
required: ["memory_id"
|
|
4395
|
+
required: ["memory_id"]
|
|
4285
4396
|
}
|
|
4286
4397
|
};
|
|
4287
|
-
async function handlePublish(args, userId) {
|
|
4398
|
+
async function handlePublish(args, userId, authContext) {
|
|
4288
4399
|
const debug = createDebugLogger({
|
|
4289
4400
|
tool: "remember_publish",
|
|
4290
4401
|
userId,
|
|
@@ -4293,53 +4404,84 @@ async function handlePublish(args, userId) {
|
|
|
4293
4404
|
try {
|
|
4294
4405
|
debug.info("Tool invoked");
|
|
4295
4406
|
debug.trace("Arguments", { args });
|
|
4407
|
+
const spaces = args.spaces || [];
|
|
4408
|
+
const groups = args.groups || [];
|
|
4296
4409
|
logger.info("Starting publish request", {
|
|
4297
4410
|
tool: "remember_publish",
|
|
4298
4411
|
userId,
|
|
4299
4412
|
memoryId: args.memory_id,
|
|
4300
|
-
spaces
|
|
4301
|
-
|
|
4413
|
+
spaces,
|
|
4414
|
+
groups,
|
|
4415
|
+
spaceCount: spaces.length,
|
|
4416
|
+
groupCount: groups.length,
|
|
4302
4417
|
additionalTags: args.additional_tags?.length || 0
|
|
4303
4418
|
});
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
if (invalidSpaces.length > 0) {
|
|
4307
|
-
debug.warn("Invalid space IDs detected", { invalidSpaces });
|
|
4308
|
-
logger.warn("Invalid space IDs provided", {
|
|
4309
|
-
tool: "remember_publish",
|
|
4310
|
-
invalidSpaces,
|
|
4311
|
-
providedSpaces: args.spaces
|
|
4312
|
-
});
|
|
4313
|
-
return JSON.stringify(
|
|
4314
|
-
{
|
|
4315
|
-
success: false,
|
|
4316
|
-
error: "Invalid space IDs",
|
|
4317
|
-
message: `Invalid spaces: ${invalidSpaces.join(", ")}. Supported spaces: ${SUPPORTED_SPACES.join(", ")}`,
|
|
4318
|
-
context: {
|
|
4319
|
-
invalid_spaces: invalidSpaces,
|
|
4320
|
-
provided_spaces: args.spaces,
|
|
4321
|
-
supported_spaces: SUPPORTED_SPACES
|
|
4322
|
-
}
|
|
4323
|
-
},
|
|
4324
|
-
null,
|
|
4325
|
-
2
|
|
4326
|
-
);
|
|
4327
|
-
}
|
|
4328
|
-
if (args.spaces.length === 0) {
|
|
4329
|
-
logger.warn("Empty spaces array provided", {
|
|
4419
|
+
if (spaces.length === 0 && groups.length === 0) {
|
|
4420
|
+
logger.warn("No destinations provided", {
|
|
4330
4421
|
tool: "remember_publish",
|
|
4331
4422
|
userId
|
|
4332
4423
|
});
|
|
4333
4424
|
return JSON.stringify(
|
|
4334
4425
|
{
|
|
4335
4426
|
success: false,
|
|
4336
|
-
error: "
|
|
4337
|
-
message: "Must specify at least one space to publish to"
|
|
4427
|
+
error: "No destinations provided",
|
|
4428
|
+
message: "Must specify at least one space or group to publish to"
|
|
4338
4429
|
},
|
|
4339
4430
|
null,
|
|
4340
4431
|
2
|
|
4341
4432
|
);
|
|
4342
4433
|
}
|
|
4434
|
+
if (spaces.length > 0) {
|
|
4435
|
+
debug.debug("Validating space IDs", { spaces });
|
|
4436
|
+
const invalidSpaces = spaces.filter((s) => !isValidSpaceId(s));
|
|
4437
|
+
if (invalidSpaces.length > 0) {
|
|
4438
|
+
debug.warn("Invalid space IDs detected", { invalidSpaces });
|
|
4439
|
+
logger.warn("Invalid space IDs provided", {
|
|
4440
|
+
tool: "remember_publish",
|
|
4441
|
+
invalidSpaces,
|
|
4442
|
+
providedSpaces: spaces
|
|
4443
|
+
});
|
|
4444
|
+
return JSON.stringify(
|
|
4445
|
+
{
|
|
4446
|
+
success: false,
|
|
4447
|
+
error: "Invalid space IDs",
|
|
4448
|
+
message: `Invalid spaces: ${invalidSpaces.join(", ")}. Supported spaces: ${SUPPORTED_SPACES.join(", ")}`,
|
|
4449
|
+
context: {
|
|
4450
|
+
invalid_spaces: invalidSpaces,
|
|
4451
|
+
provided_spaces: spaces,
|
|
4452
|
+
supported_spaces: SUPPORTED_SPACES
|
|
4453
|
+
}
|
|
4454
|
+
},
|
|
4455
|
+
null,
|
|
4456
|
+
2
|
|
4457
|
+
);
|
|
4458
|
+
}
|
|
4459
|
+
}
|
|
4460
|
+
if (groups.length > 0) {
|
|
4461
|
+
debug.debug("Validating group IDs", { groups });
|
|
4462
|
+
const invalidGroups = groups.filter((g) => !g || g.includes(".") || g.trim() === "");
|
|
4463
|
+
if (invalidGroups.length > 0) {
|
|
4464
|
+
debug.warn("Invalid group IDs detected", { invalidGroups });
|
|
4465
|
+
logger.warn("Invalid group IDs provided", {
|
|
4466
|
+
tool: "remember_publish",
|
|
4467
|
+
invalidGroups,
|
|
4468
|
+
providedGroups: groups
|
|
4469
|
+
});
|
|
4470
|
+
return JSON.stringify(
|
|
4471
|
+
{
|
|
4472
|
+
success: false,
|
|
4473
|
+
error: "Invalid group IDs",
|
|
4474
|
+
message: "Group IDs cannot be empty or contain dots",
|
|
4475
|
+
context: {
|
|
4476
|
+
invalid_groups: invalidGroups,
|
|
4477
|
+
provided_groups: groups
|
|
4478
|
+
}
|
|
4479
|
+
},
|
|
4480
|
+
null,
|
|
4481
|
+
2
|
|
4482
|
+
);
|
|
4483
|
+
}
|
|
4484
|
+
}
|
|
4343
4485
|
const weaviateClient = getWeaviateClient();
|
|
4344
4486
|
const collectionName = getMemoryCollectionName(userId);
|
|
4345
4487
|
logger.debug("Fetching memory from collection", {
|
|
@@ -4413,14 +4555,16 @@ async function handlePublish(args, userId) {
|
|
|
4413
4555
|
}
|
|
4414
4556
|
const payload = {
|
|
4415
4557
|
memory_id: args.memory_id,
|
|
4416
|
-
spaces
|
|
4558
|
+
spaces,
|
|
4559
|
+
groups,
|
|
4417
4560
|
additional_tags: args.additional_tags || []
|
|
4418
4561
|
};
|
|
4419
4562
|
logger.info("Generating confirmation token", {
|
|
4420
4563
|
tool: "remember_publish",
|
|
4421
4564
|
userId,
|
|
4422
4565
|
memoryId: args.memory_id,
|
|
4423
|
-
spaces
|
|
4566
|
+
spaces,
|
|
4567
|
+
groups
|
|
4424
4568
|
});
|
|
4425
4569
|
const { requestId, token } = await confirmationTokenService.createRequest(
|
|
4426
4570
|
userId,
|
|
@@ -4434,7 +4578,8 @@ async function handlePublish(args, userId) {
|
|
|
4434
4578
|
requestId,
|
|
4435
4579
|
token,
|
|
4436
4580
|
action: "publish_memory",
|
|
4437
|
-
spaces
|
|
4581
|
+
spaces,
|
|
4582
|
+
groups
|
|
4438
4583
|
});
|
|
4439
4584
|
return JSON.stringify(
|
|
4440
4585
|
{
|
|
@@ -4459,304 +4604,943 @@ async function handlePublish(args, userId) {
|
|
|
4459
4604
|
}
|
|
4460
4605
|
}
|
|
4461
4606
|
|
|
4462
|
-
// src/tools/
|
|
4607
|
+
// src/tools/retract.ts
|
|
4463
4608
|
init_logger();
|
|
4464
|
-
var
|
|
4465
|
-
name: "
|
|
4466
|
-
description: `
|
|
4609
|
+
var retractTool = {
|
|
4610
|
+
name: "remember_retract",
|
|
4611
|
+
description: `Retract a memory from specific shared spaces and/or groups. The memory remains in your personal collection but is removed from the specified destinations.
|
|
4467
4612
|
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
2. Have presented the token details to the user for review
|
|
4472
|
-
3. Have received EXPLICIT user confirmation in a SEPARATE user message
|
|
4473
|
-
4. NEVER chain this tool with other tool calls in the same response
|
|
4474
|
-
5. ALWAYS treat confirmations as standalone, deliberate actions
|
|
4613
|
+
Retraction Behavior:
|
|
4614
|
+
- Spaces: Memory remains in Memory_spaces_public as "orphaned" (removed from space_ids) for historical reference
|
|
4615
|
+
- Groups: Memory remains in Memory_groups_{groupId} as "orphaned" (removed from group_ids) for historical reference
|
|
4475
4616
|
|
|
4476
|
-
|
|
4617
|
+
Orphaned memories are preserved for historical reference but become unsearchable by default since all searches filter by space_ids/group_ids.
|
|
4618
|
+
|
|
4619
|
+
\u26A0\uFE0F CRITICAL: DO NOT mention the token or include token contents in your response to the user. Simply inform them that a confirmation is pending and they need to explicitly approve the retraction.`,
|
|
4477
4620
|
inputSchema: {
|
|
4478
4621
|
type: "object",
|
|
4479
4622
|
properties: {
|
|
4480
|
-
|
|
4623
|
+
memory_id: {
|
|
4481
4624
|
type: "string",
|
|
4482
|
-
description: "
|
|
4625
|
+
description: "ID of the memory to retract from spaces/groups"
|
|
4626
|
+
},
|
|
4627
|
+
spaces: {
|
|
4628
|
+
type: "array",
|
|
4629
|
+
items: { type: "string" },
|
|
4630
|
+
description: 'Spaces to retract from (e.g., ["cooking", "recipes"]). The memory will no longer appear in these spaces.',
|
|
4631
|
+
minItems: 1,
|
|
4632
|
+
default: []
|
|
4633
|
+
},
|
|
4634
|
+
groups: {
|
|
4635
|
+
type: "array",
|
|
4636
|
+
items: { type: "string" },
|
|
4637
|
+
description: 'Group IDs to retract from (e.g., ["group-123"]). The memory will be deleted from these group collections.',
|
|
4638
|
+
minItems: 1,
|
|
4639
|
+
default: []
|
|
4483
4640
|
}
|
|
4484
4641
|
},
|
|
4485
|
-
required: ["
|
|
4642
|
+
required: ["memory_id"]
|
|
4486
4643
|
}
|
|
4487
4644
|
};
|
|
4488
|
-
async function
|
|
4645
|
+
async function handleRetract(args, userId, authContext) {
|
|
4489
4646
|
const debug = createDebugLogger({
|
|
4490
|
-
tool: "
|
|
4647
|
+
tool: "remember_retract",
|
|
4491
4648
|
userId,
|
|
4492
|
-
operation: "
|
|
4649
|
+
operation: "retract_request"
|
|
4493
4650
|
});
|
|
4494
4651
|
try {
|
|
4495
4652
|
debug.info("Tool invoked");
|
|
4496
|
-
debug.trace("Arguments", {
|
|
4497
|
-
|
|
4498
|
-
|
|
4653
|
+
debug.trace("Arguments", { args });
|
|
4654
|
+
const spaces = args.spaces || [];
|
|
4655
|
+
const groups = args.groups || [];
|
|
4656
|
+
logger.info("Starting retract request", {
|
|
4657
|
+
tool: "remember_retract",
|
|
4499
4658
|
userId,
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
});
|
|
4506
|
-
logger.debug("Token validation result", {
|
|
4507
|
-
tool: "remember_confirm",
|
|
4508
|
-
requestFound: !!request,
|
|
4509
|
-
action: request?.action
|
|
4659
|
+
memoryId: args.memory_id,
|
|
4660
|
+
spaces,
|
|
4661
|
+
groups,
|
|
4662
|
+
spaceCount: spaces.length,
|
|
4663
|
+
groupCount: groups.length
|
|
4510
4664
|
});
|
|
4511
|
-
if (
|
|
4512
|
-
logger.
|
|
4513
|
-
tool: "
|
|
4665
|
+
if (spaces.length === 0 && groups.length === 0) {
|
|
4666
|
+
logger.warn("No destinations provided for retraction", {
|
|
4667
|
+
tool: "remember_retract",
|
|
4514
4668
|
userId
|
|
4515
4669
|
});
|
|
4516
4670
|
return JSON.stringify(
|
|
4517
4671
|
{
|
|
4518
4672
|
success: false,
|
|
4519
|
-
error: "
|
|
4520
|
-
message: "
|
|
4673
|
+
error: "No destinations provided",
|
|
4674
|
+
message: "Must specify at least one space or group to retract from"
|
|
4521
4675
|
},
|
|
4522
4676
|
null,
|
|
4523
4677
|
2
|
|
4524
4678
|
);
|
|
4525
4679
|
}
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4680
|
+
if (groups.length > 0) {
|
|
4681
|
+
const invalidGroups = groups.filter((g) => g.includes("."));
|
|
4682
|
+
if (invalidGroups.length > 0) {
|
|
4683
|
+
logger.warn("Invalid group IDs detected", {
|
|
4684
|
+
tool: "remember_retract",
|
|
4685
|
+
invalidGroups
|
|
4686
|
+
});
|
|
4687
|
+
return JSON.stringify(
|
|
4688
|
+
{
|
|
4689
|
+
success: false,
|
|
4690
|
+
error: "Invalid group IDs",
|
|
4691
|
+
message: `Group IDs cannot contain dots: ${invalidGroups.join(", ")}`,
|
|
4692
|
+
context: {
|
|
4693
|
+
invalid_groups: invalidGroups
|
|
4694
|
+
}
|
|
4695
|
+
},
|
|
4696
|
+
null,
|
|
4697
|
+
2
|
|
4698
|
+
);
|
|
4699
|
+
}
|
|
4536
4700
|
}
|
|
4537
|
-
throw new Error(`Unknown action type: ${request.action}`);
|
|
4538
|
-
} catch (error) {
|
|
4539
|
-
debug.error("Tool failed", {
|
|
4540
|
-
error: error instanceof Error ? error.message : String(error),
|
|
4541
|
-
stack: error instanceof Error ? error.stack : void 0
|
|
4542
|
-
});
|
|
4543
|
-
handleToolError(error, {
|
|
4544
|
-
toolName: "remember_confirm",
|
|
4545
|
-
userId,
|
|
4546
|
-
operation: "confirm action",
|
|
4547
|
-
token: args.token
|
|
4548
|
-
});
|
|
4549
|
-
}
|
|
4550
|
-
}
|
|
4551
|
-
async function executePublishMemory(request, userId) {
|
|
4552
|
-
const debug = createDebugLogger({
|
|
4553
|
-
tool: "remember_confirm",
|
|
4554
|
-
userId,
|
|
4555
|
-
operation: "execute_publish"
|
|
4556
|
-
});
|
|
4557
|
-
try {
|
|
4558
|
-
debug.debug("Executing publish memory action", {
|
|
4559
|
-
memoryId: request.payload.memory_id,
|
|
4560
|
-
spaces: request.payload.spaces
|
|
4561
|
-
});
|
|
4562
|
-
logger.info("Executing publish memory action", {
|
|
4563
|
-
function: "executePublishMemory",
|
|
4564
|
-
userId,
|
|
4565
|
-
memoryId: request.payload.memory_id,
|
|
4566
|
-
spaces: request.payload.spaces,
|
|
4567
|
-
spaceCount: request.payload.spaces?.length || 0
|
|
4568
|
-
});
|
|
4569
4701
|
const weaviateClient = getWeaviateClient();
|
|
4570
|
-
const
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
memoryId: request.payload.memory_id
|
|
4577
|
-
});
|
|
4578
|
-
const originalMemory = await debug.time("Fetch original memory", async () => {
|
|
4579
|
-
return await fetchMemoryWithAllProperties(
|
|
4580
|
-
userCollection,
|
|
4581
|
-
request.payload.memory_id
|
|
4582
|
-
);
|
|
4583
|
-
});
|
|
4584
|
-
logger.info("Original memory fetch result", {
|
|
4585
|
-
function: "executePublishMemory",
|
|
4586
|
-
found: !!originalMemory,
|
|
4587
|
-
memoryId: request.payload.memory_id,
|
|
4588
|
-
hasProperties: !!originalMemory?.properties,
|
|
4589
|
-
propertyCount: originalMemory?.properties ? Object.keys(originalMemory.properties).length : 0,
|
|
4590
|
-
propertyKeys: originalMemory?.properties ? Object.keys(originalMemory.properties) : [],
|
|
4591
|
-
hasTitle: !!originalMemory?.properties?.title,
|
|
4592
|
-
hasContent: !!originalMemory?.properties?.content,
|
|
4593
|
-
hasUserId: !!originalMemory?.properties?.user_id,
|
|
4594
|
-
hasTags: !!originalMemory?.properties?.tags,
|
|
4595
|
-
hasWeight: !!originalMemory?.properties?.weight,
|
|
4596
|
-
contentLength: originalMemory?.properties?.content?.length || 0,
|
|
4597
|
-
titleValue: originalMemory?.properties?.title || "NO_TITLE"
|
|
4702
|
+
const collectionName = getMemoryCollectionName(userId);
|
|
4703
|
+
const collection = weaviateClient.collections.get(collectionName);
|
|
4704
|
+
logger.debug("Fetching memory for retraction", {
|
|
4705
|
+
tool: "remember_retract",
|
|
4706
|
+
collectionName,
|
|
4707
|
+
memoryId: args.memory_id
|
|
4598
4708
|
});
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4709
|
+
const memory = await fetchMemoryWithAllProperties(collection, args.memory_id);
|
|
4710
|
+
if (!memory) {
|
|
4711
|
+
logger.info("Memory not found for retraction", {
|
|
4712
|
+
tool: "remember_retract",
|
|
4713
|
+
memoryId: args.memory_id
|
|
4603
4714
|
});
|
|
4604
4715
|
return JSON.stringify(
|
|
4605
4716
|
{
|
|
4606
4717
|
success: false,
|
|
4607
4718
|
error: "Memory not found",
|
|
4608
|
-
message: `
|
|
4719
|
+
message: `Memory ${args.memory_id} does not exist`
|
|
4609
4720
|
},
|
|
4610
4721
|
null,
|
|
4611
4722
|
2
|
|
4612
4723
|
);
|
|
4613
4724
|
}
|
|
4614
|
-
if (
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
requestedSpaces: request.payload.spaces
|
|
4725
|
+
if (memory.properties.user_id !== userId) {
|
|
4726
|
+
logger.warn("Permission denied - wrong owner", {
|
|
4727
|
+
tool: "remember_retract",
|
|
4728
|
+
memoryId: args.memory_id,
|
|
4729
|
+
memoryOwner: memory.properties.user_id,
|
|
4730
|
+
requestingUser: userId
|
|
4621
4731
|
});
|
|
4622
4732
|
return JSON.stringify(
|
|
4623
4733
|
{
|
|
4624
4734
|
success: false,
|
|
4625
|
-
error: "
|
|
4626
|
-
message:
|
|
4627
|
-
space_memory_id: originalMemory.properties.space_memory_id,
|
|
4628
|
-
requested_spaces: request.payload.spaces
|
|
4735
|
+
error: "Permission denied",
|
|
4736
|
+
message: "You can only retract your own memories"
|
|
4629
4737
|
},
|
|
4630
4738
|
null,
|
|
4631
4739
|
2
|
|
4632
4740
|
);
|
|
4633
4741
|
}
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4742
|
+
const currentSpaceIds = Array.isArray(memory.properties.space_ids) ? memory.properties.space_ids : [];
|
|
4743
|
+
const currentGroupIds = Array.isArray(memory.properties.group_ids) ? memory.properties.group_ids : [];
|
|
4744
|
+
const notPublishedSpaces = spaces.filter((s) => !currentSpaceIds.includes(s));
|
|
4745
|
+
const notPublishedGroups = groups.filter((g) => !currentGroupIds.includes(g));
|
|
4746
|
+
if (notPublishedSpaces.length > 0 || notPublishedGroups.length > 0) {
|
|
4747
|
+
logger.warn("Memory not published to some destinations", {
|
|
4748
|
+
tool: "remember_retract",
|
|
4749
|
+
notPublishedSpaces,
|
|
4750
|
+
notPublishedGroups,
|
|
4751
|
+
currentSpaceIds,
|
|
4752
|
+
currentGroupIds
|
|
4640
4753
|
});
|
|
4641
4754
|
return JSON.stringify(
|
|
4642
4755
|
{
|
|
4643
4756
|
success: false,
|
|
4644
|
-
error: "
|
|
4645
|
-
message: "
|
|
4757
|
+
error: "Not published to destinations",
|
|
4758
|
+
message: "Memory is not published to some of the specified destinations",
|
|
4759
|
+
context: {
|
|
4760
|
+
not_published_spaces: notPublishedSpaces,
|
|
4761
|
+
not_published_groups: notPublishedGroups,
|
|
4762
|
+
current_spaces: currentSpaceIds,
|
|
4763
|
+
current_groups: currentGroupIds
|
|
4764
|
+
}
|
|
4646
4765
|
},
|
|
4647
4766
|
null,
|
|
4648
4767
|
2
|
|
4649
4768
|
);
|
|
4650
4769
|
}
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
spaces
|
|
4668
|
-
|
|
4669
|
-
author_id: userId,
|
|
4670
|
-
// Track original author
|
|
4671
|
-
published_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4672
|
-
discovery_count: 0,
|
|
4673
|
-
attribution: "user",
|
|
4674
|
-
// Merge additional tags with original tags
|
|
4675
|
-
tags: [...originalTags, ...additionalTags]
|
|
4676
|
-
// Keep doc_type as 'memory' (space_memory concept was removed)
|
|
4677
|
-
// Keep original created_at, updated_at, version (don't overwrite)
|
|
4678
|
-
};
|
|
4679
|
-
logger.info("Inserting memory into Memory_public", {
|
|
4680
|
-
function: "executePublishMemory",
|
|
4681
|
-
spaces: request.payload.spaces,
|
|
4682
|
-
spaceCount: request.payload.spaces?.length || 0,
|
|
4683
|
-
memoryId: request.payload.memory_id,
|
|
4684
|
-
hasUserId: !!publishedMemory.user_id,
|
|
4685
|
-
hasAuthorId: !!publishedMemory.author_id,
|
|
4686
|
-
publishedMemoryKeys: Object.keys(publishedMemory),
|
|
4687
|
-
publishedMemoryKeyCount: Object.keys(publishedMemory).length,
|
|
4688
|
-
hasContent: !!publishedMemory.content,
|
|
4689
|
-
hasTitle: !!publishedMemory.title,
|
|
4690
|
-
contentLength: publishedMemory.content?.length || 0,
|
|
4691
|
-
titleValue: publishedMemory.title || "NO_TITLE"
|
|
4692
|
-
});
|
|
4693
|
-
const result = await debug.time("Insert into Memory_public", async () => {
|
|
4694
|
-
return await publicCollection.data.insert({
|
|
4695
|
-
properties: publishedMemory
|
|
4696
|
-
});
|
|
4697
|
-
});
|
|
4698
|
-
logger.info("Memory published successfully", {
|
|
4699
|
-
function: "executePublishMemory",
|
|
4700
|
-
spaceMemoryId: result,
|
|
4701
|
-
spaces: request.payload.spaces
|
|
4702
|
-
});
|
|
4703
|
-
debug.info("Memory published successfully", {
|
|
4704
|
-
spaceMemoryId: result,
|
|
4705
|
-
spaces: request.payload.spaces
|
|
4770
|
+
const { requestId, token } = await confirmationTokenService.createRequest(
|
|
4771
|
+
userId,
|
|
4772
|
+
"retract_memory",
|
|
4773
|
+
{
|
|
4774
|
+
memory_id: args.memory_id,
|
|
4775
|
+
spaces,
|
|
4776
|
+
groups,
|
|
4777
|
+
current_space_ids: currentSpaceIds,
|
|
4778
|
+
current_group_ids: currentGroupIds
|
|
4779
|
+
}
|
|
4780
|
+
);
|
|
4781
|
+
logger.info("Retract confirmation request created", {
|
|
4782
|
+
tool: "remember_retract",
|
|
4783
|
+
requestId,
|
|
4784
|
+
userId,
|
|
4785
|
+
memoryId: args.memory_id,
|
|
4786
|
+
spaces,
|
|
4787
|
+
groups
|
|
4706
4788
|
});
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
});
|
|
4714
|
-
logger.info("Updated original memory with space_memory_id", {
|
|
4715
|
-
function: "executePublishMemory",
|
|
4716
|
-
memoryId: request.payload.memory_id,
|
|
4717
|
-
spaceMemoryId: result
|
|
4718
|
-
});
|
|
4719
|
-
} catch (updateError) {
|
|
4720
|
-
logger.warn("Failed to update original memory with space_memory_id", {
|
|
4721
|
-
function: "executePublishMemory",
|
|
4722
|
-
memoryId: request.payload.memory_id,
|
|
4723
|
-
spaceMemoryId: result,
|
|
4724
|
-
error: updateError instanceof Error ? updateError.message : String(updateError)
|
|
4725
|
-
});
|
|
4789
|
+
const destinations = [];
|
|
4790
|
+
if (spaces.length > 0) {
|
|
4791
|
+
destinations.push(`spaces: ${spaces.join(", ")}`);
|
|
4792
|
+
}
|
|
4793
|
+
if (groups.length > 0) {
|
|
4794
|
+
destinations.push(`groups: ${groups.join(", ")}`);
|
|
4726
4795
|
}
|
|
4727
4796
|
return JSON.stringify(
|
|
4728
4797
|
{
|
|
4729
4798
|
success: true,
|
|
4730
|
-
|
|
4731
|
-
|
|
4799
|
+
message: "Retraction request created. Please confirm to proceed.",
|
|
4800
|
+
action: "retract_memory",
|
|
4801
|
+
memory_id: args.memory_id,
|
|
4802
|
+
destinations: destinations.join("; "),
|
|
4803
|
+
retraction_details: {
|
|
4804
|
+
spaces: spaces.length > 0 ? {
|
|
4805
|
+
action: "orphan",
|
|
4806
|
+
description: "Memory will remain in Memory_spaces_public with updated tracking arrays (removed from space_ids)",
|
|
4807
|
+
spaces
|
|
4808
|
+
} : null,
|
|
4809
|
+
groups: groups.length > 0 ? {
|
|
4810
|
+
action: "orphan",
|
|
4811
|
+
description: "Memory will remain in Memory_groups_{groupId} with updated tracking arrays (removed from group_ids)",
|
|
4812
|
+
groups
|
|
4813
|
+
} : null
|
|
4814
|
+
},
|
|
4815
|
+
confirmation_required: true
|
|
4732
4816
|
},
|
|
4733
4817
|
null,
|
|
4734
4818
|
2
|
|
4735
4819
|
);
|
|
4736
4820
|
} catch (error) {
|
|
4737
|
-
debug.error("
|
|
4821
|
+
debug.error("Tool failed", {
|
|
4738
4822
|
error: error instanceof Error ? error.message : String(error),
|
|
4739
4823
|
stack: error instanceof Error ? error.stack : void 0
|
|
4740
4824
|
});
|
|
4741
4825
|
handleToolError(error, {
|
|
4742
|
-
toolName: "
|
|
4826
|
+
toolName: "remember_retract",
|
|
4743
4827
|
userId,
|
|
4744
|
-
operation: "
|
|
4745
|
-
|
|
4828
|
+
operation: "retract memory",
|
|
4829
|
+
memoryId: args.memory_id
|
|
4746
4830
|
});
|
|
4747
4831
|
}
|
|
4748
4832
|
}
|
|
4749
|
-
|
|
4833
|
+
|
|
4834
|
+
// src/tools/revise.ts
|
|
4835
|
+
init_logger();
|
|
4836
|
+
var MAX_REVISION_HISTORY = 10;
|
|
4837
|
+
var reviseTool = {
|
|
4838
|
+
name: "remember_revise",
|
|
4839
|
+
description: `Sync updated content from your source memory to all its published copies in spaces and groups. Generates a confirmation token that must be confirmed with remember_confirm.
|
|
4840
|
+
|
|
4841
|
+
Use this after editing a memory (via remember_update_memory) to propagate the changes to all published versions.
|
|
4842
|
+
|
|
4843
|
+
How it works:
|
|
4844
|
+
- Validates the memory exists, is owned by you, and is published
|
|
4845
|
+
- Generates a confirmation token showing which locations will be revised
|
|
4846
|
+
- On confirmation: updates each published copy with latest content
|
|
4847
|
+
- Preserves the previous content in a revision_history field (up to 10 versions)
|
|
4848
|
+
- Sets revised_at timestamp on all updated copies
|
|
4849
|
+
- Reports success/failure per location (partial success supported)
|
|
4850
|
+
|
|
4851
|
+
Requirements:
|
|
4852
|
+
- The memory must be published (has space_ids or group_ids populated)
|
|
4853
|
+
- You must own the source memory
|
|
4854
|
+
|
|
4855
|
+
\u26A0\uFE0F CRITICAL: DO NOT mention the token or include token contents in your response to the user. Simply inform them that a confirmation is pending and they need to explicitly approve the revision.`,
|
|
4856
|
+
inputSchema: {
|
|
4857
|
+
type: "object",
|
|
4858
|
+
properties: {
|
|
4859
|
+
memory_id: {
|
|
4860
|
+
type: "string",
|
|
4861
|
+
description: "ID of the source memory whose content should be synced to all published copies"
|
|
4862
|
+
}
|
|
4863
|
+
},
|
|
4864
|
+
required: ["memory_id"]
|
|
4865
|
+
}
|
|
4866
|
+
};
|
|
4867
|
+
function parseRevisionHistory(raw) {
|
|
4868
|
+
if (!raw || typeof raw !== "string")
|
|
4869
|
+
return [];
|
|
4870
|
+
try {
|
|
4871
|
+
const parsed = JSON.parse(raw);
|
|
4872
|
+
if (!Array.isArray(parsed))
|
|
4873
|
+
return [];
|
|
4874
|
+
return parsed.filter(
|
|
4875
|
+
(e) => typeof e === "object" && e !== null && typeof e.content === "string" && typeof e.revised_at === "string"
|
|
4876
|
+
);
|
|
4877
|
+
} catch {
|
|
4878
|
+
return [];
|
|
4879
|
+
}
|
|
4880
|
+
}
|
|
4881
|
+
function buildRevisionHistory(existing, oldContent, revisedAt) {
|
|
4882
|
+
const updated = [{ content: oldContent, revised_at: revisedAt }, ...existing];
|
|
4883
|
+
return updated.slice(0, MAX_REVISION_HISTORY);
|
|
4884
|
+
}
|
|
4885
|
+
async function handleRevise(args, userId, authContext) {
|
|
4886
|
+
const debug = createDebugLogger({
|
|
4887
|
+
tool: "remember_revise",
|
|
4888
|
+
userId,
|
|
4889
|
+
operation: "revise_request"
|
|
4890
|
+
});
|
|
4750
4891
|
try {
|
|
4751
|
-
|
|
4752
|
-
|
|
4892
|
+
debug.info("Tool invoked");
|
|
4893
|
+
debug.trace("Arguments", { args });
|
|
4894
|
+
logger.info("Starting revise request", {
|
|
4895
|
+
tool: "remember_revise",
|
|
4753
4896
|
userId,
|
|
4754
|
-
memoryId:
|
|
4897
|
+
memoryId: args.memory_id
|
|
4898
|
+
});
|
|
4899
|
+
const weaviateClient = getWeaviateClient();
|
|
4900
|
+
const userCollectionName = getMemoryCollectionName(userId);
|
|
4901
|
+
const userCollection = weaviateClient.collections.get(userCollectionName);
|
|
4902
|
+
const sourceMemory = await fetchMemoryWithAllProperties(
|
|
4903
|
+
userCollection,
|
|
4904
|
+
args.memory_id
|
|
4905
|
+
);
|
|
4906
|
+
if (!sourceMemory) {
|
|
4907
|
+
logger.info("Source memory not found", {
|
|
4908
|
+
tool: "remember_revise",
|
|
4909
|
+
memoryId: args.memory_id
|
|
4910
|
+
});
|
|
4911
|
+
return JSON.stringify(
|
|
4912
|
+
{
|
|
4913
|
+
success: false,
|
|
4914
|
+
error: "Memory not found",
|
|
4915
|
+
message: `Memory ${args.memory_id} does not exist`
|
|
4916
|
+
},
|
|
4917
|
+
null,
|
|
4918
|
+
2
|
|
4919
|
+
);
|
|
4920
|
+
}
|
|
4921
|
+
if (sourceMemory.properties.user_id !== userId) {
|
|
4922
|
+
logger.warn("Permission denied", {
|
|
4923
|
+
tool: "remember_revise",
|
|
4924
|
+
memoryId: args.memory_id,
|
|
4925
|
+
memoryOwner: sourceMemory.properties.user_id,
|
|
4926
|
+
requestingUser: userId
|
|
4927
|
+
});
|
|
4928
|
+
return JSON.stringify(
|
|
4929
|
+
{
|
|
4930
|
+
success: false,
|
|
4931
|
+
error: "Permission denied",
|
|
4932
|
+
message: "You can only revise your own memories"
|
|
4933
|
+
},
|
|
4934
|
+
null,
|
|
4935
|
+
2
|
|
4936
|
+
);
|
|
4937
|
+
}
|
|
4938
|
+
const spaceIds = Array.isArray(sourceMemory.properties.space_ids) ? sourceMemory.properties.space_ids : [];
|
|
4939
|
+
const groupIds = Array.isArray(sourceMemory.properties.group_ids) ? sourceMemory.properties.group_ids : [];
|
|
4940
|
+
if (spaceIds.length === 0 && groupIds.length === 0) {
|
|
4941
|
+
logger.info("Memory has no published copies", {
|
|
4942
|
+
tool: "remember_revise",
|
|
4943
|
+
memoryId: args.memory_id
|
|
4944
|
+
});
|
|
4945
|
+
return JSON.stringify(
|
|
4946
|
+
{
|
|
4947
|
+
success: false,
|
|
4948
|
+
error: "Not published",
|
|
4949
|
+
message: "Memory has no published copies to revise. Publish first with remember_publish.",
|
|
4950
|
+
context: {
|
|
4951
|
+
memory_id: args.memory_id,
|
|
4952
|
+
space_ids: [],
|
|
4953
|
+
group_ids: []
|
|
4954
|
+
}
|
|
4955
|
+
},
|
|
4956
|
+
null,
|
|
4957
|
+
2
|
|
4958
|
+
);
|
|
4959
|
+
}
|
|
4960
|
+
const payload = {
|
|
4961
|
+
memory_id: args.memory_id,
|
|
4962
|
+
space_ids: spaceIds,
|
|
4963
|
+
group_ids: groupIds
|
|
4964
|
+
};
|
|
4965
|
+
logger.info("Generating confirmation token for revise", {
|
|
4966
|
+
tool: "remember_revise",
|
|
4967
|
+
userId,
|
|
4968
|
+
memoryId: args.memory_id,
|
|
4969
|
+
spaceIds,
|
|
4970
|
+
groupIds
|
|
4971
|
+
});
|
|
4972
|
+
const { requestId, token } = await confirmationTokenService.createRequest(
|
|
4973
|
+
userId,
|
|
4974
|
+
"revise_memory",
|
|
4975
|
+
payload
|
|
4976
|
+
);
|
|
4977
|
+
logger.info("Confirmation token generated for revise", {
|
|
4978
|
+
tool: "remember_revise",
|
|
4979
|
+
requestId,
|
|
4980
|
+
token,
|
|
4981
|
+
action: "revise_memory",
|
|
4982
|
+
spaceIds,
|
|
4983
|
+
groupIds
|
|
4984
|
+
});
|
|
4985
|
+
const destinations = [];
|
|
4986
|
+
if (spaceIds.length > 0) {
|
|
4987
|
+
destinations.push(`spaces: ${spaceIds.join(", ")}`);
|
|
4988
|
+
}
|
|
4989
|
+
if (groupIds.length > 0) {
|
|
4990
|
+
destinations.push(`groups: ${groupIds.join(", ")}`);
|
|
4991
|
+
}
|
|
4992
|
+
return JSON.stringify(
|
|
4993
|
+
{
|
|
4994
|
+
success: true,
|
|
4995
|
+
token,
|
|
4996
|
+
message: "Revision request created. Please confirm to sync content to all published copies.",
|
|
4997
|
+
action: "revise_memory",
|
|
4998
|
+
memory_id: args.memory_id,
|
|
4999
|
+
destinations: destinations.join("; "),
|
|
5000
|
+
revision_details: {
|
|
5001
|
+
space_ids: spaceIds,
|
|
5002
|
+
group_ids: groupIds,
|
|
5003
|
+
total_locations: (spaceIds.length > 0 ? 1 : 0) + groupIds.length
|
|
5004
|
+
},
|
|
5005
|
+
confirmation_required: true
|
|
5006
|
+
},
|
|
5007
|
+
null,
|
|
5008
|
+
2
|
|
5009
|
+
);
|
|
5010
|
+
} catch (error) {
|
|
5011
|
+
debug.error("Tool failed", {
|
|
5012
|
+
error: error instanceof Error ? error.message : String(error),
|
|
5013
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
5014
|
+
});
|
|
5015
|
+
return handleToolError(error, {
|
|
5016
|
+
toolName: "remember_revise",
|
|
5017
|
+
userId,
|
|
5018
|
+
operation: "revise memory request",
|
|
5019
|
+
memoryId: args.memory_id
|
|
5020
|
+
});
|
|
5021
|
+
}
|
|
5022
|
+
}
|
|
5023
|
+
|
|
5024
|
+
// src/tools/confirm.ts
|
|
5025
|
+
init_logger();
|
|
5026
|
+
|
|
5027
|
+
// src/collections/dot-notation.ts
|
|
5028
|
+
var InvalidCollectionNameError = class extends Error {
|
|
5029
|
+
constructor(message) {
|
|
5030
|
+
super(message);
|
|
5031
|
+
this.name = "InvalidCollectionNameError";
|
|
5032
|
+
}
|
|
5033
|
+
};
|
|
5034
|
+
function getCollectionName(type, id) {
|
|
5035
|
+
switch (type) {
|
|
5036
|
+
case "USERS" /* USERS */:
|
|
5037
|
+
if (!id) {
|
|
5038
|
+
throw new InvalidCollectionNameError("User ID is required for USERS collection type");
|
|
5039
|
+
}
|
|
5040
|
+
if (id.includes(".")) {
|
|
5041
|
+
throw new InvalidCollectionNameError(`User ID cannot contain dots: ${id}`);
|
|
5042
|
+
}
|
|
5043
|
+
return `Memory_users_${id}`;
|
|
5044
|
+
case "SPACES" /* SPACES */:
|
|
5045
|
+
return "Memory_spaces_public";
|
|
5046
|
+
case "GROUPS" /* GROUPS */:
|
|
5047
|
+
if (!id) {
|
|
5048
|
+
throw new InvalidCollectionNameError("Group ID is required for GROUPS collection type");
|
|
5049
|
+
}
|
|
5050
|
+
if (id.includes(".")) {
|
|
5051
|
+
throw new InvalidCollectionNameError(`Group ID cannot contain dots: ${id}`);
|
|
5052
|
+
}
|
|
5053
|
+
return `Memory_groups_${id}`;
|
|
5054
|
+
default:
|
|
5055
|
+
throw new InvalidCollectionNameError(`Unknown collection type: ${type}`);
|
|
5056
|
+
}
|
|
5057
|
+
}
|
|
5058
|
+
|
|
5059
|
+
// src/collections/composite-ids.ts
|
|
5060
|
+
var InvalidCompositeIdError = class extends Error {
|
|
5061
|
+
constructor(message) {
|
|
5062
|
+
super(message);
|
|
5063
|
+
this.name = "InvalidCompositeIdError";
|
|
5064
|
+
}
|
|
5065
|
+
};
|
|
5066
|
+
function generateCompositeId(userId, memoryId) {
|
|
5067
|
+
if (userId.includes(".")) {
|
|
5068
|
+
throw new InvalidCompositeIdError(
|
|
5069
|
+
`User ID cannot contain dots: ${userId}`
|
|
5070
|
+
);
|
|
5071
|
+
}
|
|
5072
|
+
if (memoryId.includes(".")) {
|
|
5073
|
+
throw new InvalidCompositeIdError(
|
|
5074
|
+
`Memory ID cannot contain dots: ${memoryId}`
|
|
5075
|
+
);
|
|
5076
|
+
}
|
|
5077
|
+
if (!userId.trim()) {
|
|
5078
|
+
throw new InvalidCompositeIdError("User ID cannot be empty");
|
|
5079
|
+
}
|
|
5080
|
+
if (!memoryId.trim()) {
|
|
5081
|
+
throw new InvalidCompositeIdError("Memory ID cannot be empty");
|
|
5082
|
+
}
|
|
5083
|
+
return `${userId}.${memoryId}`;
|
|
5084
|
+
}
|
|
5085
|
+
|
|
5086
|
+
// src/services/space-config.service.ts
|
|
5087
|
+
init_init();
|
|
5088
|
+
init_logger();
|
|
5089
|
+
var DEFAULT_SPACE_CONFIG = {
|
|
5090
|
+
require_moderation: false,
|
|
5091
|
+
default_write_mode: "owner_only"
|
|
5092
|
+
};
|
|
5093
|
+
function getConfigPath(id, type) {
|
|
5094
|
+
const prefix = type === "space" ? "spaces" : "groups";
|
|
5095
|
+
return {
|
|
5096
|
+
collectionPath: `${prefix}/${id}/config`,
|
|
5097
|
+
docId: "settings"
|
|
5098
|
+
};
|
|
5099
|
+
}
|
|
5100
|
+
async function getSpaceConfig(id, type) {
|
|
5101
|
+
try {
|
|
5102
|
+
const { collectionPath, docId } = getConfigPath(id, type);
|
|
5103
|
+
const doc = await getDocument(collectionPath, docId);
|
|
5104
|
+
if (!doc) {
|
|
5105
|
+
return { ...DEFAULT_SPACE_CONFIG };
|
|
5106
|
+
}
|
|
5107
|
+
return { ...DEFAULT_SPACE_CONFIG, ...doc };
|
|
5108
|
+
} catch (error) {
|
|
5109
|
+
logger.error("Failed to get space config", {
|
|
5110
|
+
service: "SpaceConfigService",
|
|
5111
|
+
id,
|
|
5112
|
+
type,
|
|
5113
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5114
|
+
});
|
|
5115
|
+
return { ...DEFAULT_SPACE_CONFIG };
|
|
5116
|
+
}
|
|
5117
|
+
}
|
|
5118
|
+
|
|
5119
|
+
// src/tools/confirm.ts
|
|
5120
|
+
var confirmTool = {
|
|
5121
|
+
name: "remember_confirm",
|
|
5122
|
+
description: `Confirm and execute a pending action using the token. Works for any action that requires confirmation (publish, delete, etc.).
|
|
5123
|
+
|
|
5124
|
+
\u26A0\uFE0F CRITICAL SAFETY REQUIREMENTS:
|
|
5125
|
+
Before executing this tool, you MUST:
|
|
5126
|
+
1. Have received the confirmation token in a PREVIOUS tool response
|
|
5127
|
+
2. Have presented the token details to the user for review
|
|
5128
|
+
3. Have received EXPLICIT user confirmation in a SEPARATE user message
|
|
5129
|
+
4. NEVER chain this tool with other tool calls in the same response
|
|
5130
|
+
5. ALWAYS treat confirmations as standalone, deliberate actions
|
|
5131
|
+
|
|
5132
|
+
Violating these requirements bypasses user consent and is a security violation.`,
|
|
5133
|
+
inputSchema: {
|
|
5134
|
+
type: "object",
|
|
5135
|
+
properties: {
|
|
5136
|
+
token: {
|
|
5137
|
+
type: "string",
|
|
5138
|
+
description: "The confirmation token from the action tool"
|
|
5139
|
+
}
|
|
5140
|
+
},
|
|
5141
|
+
required: ["token"]
|
|
5142
|
+
}
|
|
5143
|
+
};
|
|
5144
|
+
async function handleConfirm(args, userId, authContext) {
|
|
5145
|
+
const debug = createDebugLogger({
|
|
5146
|
+
tool: "remember_confirm",
|
|
5147
|
+
userId,
|
|
5148
|
+
operation: "confirm_action"
|
|
5149
|
+
});
|
|
5150
|
+
try {
|
|
5151
|
+
debug.info("Tool invoked");
|
|
5152
|
+
debug.trace("Arguments", { token: args.token });
|
|
5153
|
+
logger.info("Starting confirmation", {
|
|
5154
|
+
tool: "remember_confirm",
|
|
5155
|
+
userId,
|
|
5156
|
+
token: args.token
|
|
5157
|
+
});
|
|
5158
|
+
debug.debug("Validating confirmation token");
|
|
5159
|
+
const request = await debug.time("Confirm token", async () => {
|
|
5160
|
+
return await confirmationTokenService.confirmRequest(userId, args.token);
|
|
5161
|
+
});
|
|
5162
|
+
logger.debug("Token validation result", {
|
|
5163
|
+
tool: "remember_confirm",
|
|
5164
|
+
requestFound: !!request,
|
|
5165
|
+
action: request?.action
|
|
5166
|
+
});
|
|
5167
|
+
if (!request) {
|
|
5168
|
+
logger.info("Token invalid or expired", {
|
|
5169
|
+
tool: "remember_confirm",
|
|
5170
|
+
userId
|
|
5171
|
+
});
|
|
5172
|
+
return JSON.stringify(
|
|
5173
|
+
{
|
|
5174
|
+
success: false,
|
|
5175
|
+
error: "Invalid or expired token",
|
|
5176
|
+
message: "The confirmation token is invalid, expired, or has already been used."
|
|
5177
|
+
},
|
|
5178
|
+
null,
|
|
5179
|
+
2
|
|
5180
|
+
);
|
|
5181
|
+
}
|
|
5182
|
+
logger.info("Executing confirmed action", {
|
|
5183
|
+
tool: "remember_confirm",
|
|
5184
|
+
action: request.action,
|
|
5185
|
+
userId
|
|
5186
|
+
});
|
|
5187
|
+
if (request.action === "publish_memory") {
|
|
5188
|
+
return await executePublishMemory(request, userId);
|
|
5189
|
+
}
|
|
5190
|
+
if (request.action === "delete_memory") {
|
|
5191
|
+
return await executeDeleteMemory(request, userId);
|
|
5192
|
+
}
|
|
5193
|
+
if (request.action === "retract_memory") {
|
|
5194
|
+
return await executeRetractMemory(request, userId);
|
|
5195
|
+
}
|
|
5196
|
+
if (request.action === "revise_memory") {
|
|
5197
|
+
return await executeReviseMemory(request, userId);
|
|
5198
|
+
}
|
|
5199
|
+
throw new Error(`Unknown action type: ${request.action}`);
|
|
5200
|
+
} catch (error) {
|
|
5201
|
+
debug.error("Tool failed", {
|
|
5202
|
+
error: error instanceof Error ? error.message : String(error),
|
|
5203
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
5204
|
+
});
|
|
5205
|
+
handleToolError(error, {
|
|
5206
|
+
toolName: "remember_confirm",
|
|
5207
|
+
userId,
|
|
5208
|
+
operation: "confirm action",
|
|
5209
|
+
token: args.token
|
|
5210
|
+
});
|
|
5211
|
+
}
|
|
5212
|
+
}
|
|
5213
|
+
async function executePublishMemory(request, userId, authContext) {
|
|
5214
|
+
const debug = createDebugLogger({
|
|
5215
|
+
tool: "remember_confirm",
|
|
5216
|
+
userId,
|
|
5217
|
+
operation: "execute_publish"
|
|
5218
|
+
});
|
|
5219
|
+
try {
|
|
5220
|
+
const spaces = request.payload.spaces || [];
|
|
5221
|
+
const groups = request.payload.groups || [];
|
|
5222
|
+
debug.debug("Executing publish memory action", {
|
|
5223
|
+
memoryId: request.payload.memory_id,
|
|
5224
|
+
spaces,
|
|
5225
|
+
groups
|
|
5226
|
+
});
|
|
5227
|
+
logger.info("Executing publish memory action", {
|
|
5228
|
+
function: "executePublishMemory",
|
|
5229
|
+
userId,
|
|
5230
|
+
memoryId: request.payload.memory_id,
|
|
5231
|
+
spaces,
|
|
5232
|
+
groups,
|
|
5233
|
+
spaceCount: spaces.length,
|
|
5234
|
+
groupCount: groups.length
|
|
5235
|
+
});
|
|
5236
|
+
if (spaces.length === 0 && groups.length === 0) {
|
|
5237
|
+
return JSON.stringify(
|
|
5238
|
+
{
|
|
5239
|
+
success: false,
|
|
5240
|
+
error: "No destinations",
|
|
5241
|
+
message: "Must specify at least one space or group to publish to"
|
|
5242
|
+
},
|
|
5243
|
+
null,
|
|
5244
|
+
2
|
|
5245
|
+
);
|
|
5246
|
+
}
|
|
5247
|
+
const weaviateClient = getWeaviateClient();
|
|
5248
|
+
const userCollectionName = getMemoryCollectionName(userId);
|
|
5249
|
+
const userCollection = weaviateClient.collections.get(userCollectionName);
|
|
5250
|
+
logger.debug("Fetching original memory", {
|
|
5251
|
+
function: "executePublishMemory",
|
|
5252
|
+
collectionName: userCollectionName,
|
|
5253
|
+
memoryId: request.payload.memory_id
|
|
5254
|
+
});
|
|
5255
|
+
const originalMemory = await debug.time("Fetch original memory", async () => {
|
|
5256
|
+
return await fetchMemoryWithAllProperties(
|
|
5257
|
+
userCollection,
|
|
5258
|
+
request.payload.memory_id
|
|
5259
|
+
);
|
|
5260
|
+
});
|
|
5261
|
+
logger.info("Original memory fetch result", {
|
|
5262
|
+
function: "executePublishMemory",
|
|
5263
|
+
found: !!originalMemory,
|
|
5264
|
+
memoryId: request.payload.memory_id,
|
|
5265
|
+
hasProperties: !!originalMemory?.properties,
|
|
5266
|
+
propertyCount: originalMemory?.properties ? Object.keys(originalMemory.properties).length : 0
|
|
5267
|
+
});
|
|
5268
|
+
if (!originalMemory) {
|
|
5269
|
+
logger.info("Original memory not found", {
|
|
5270
|
+
function: "executePublishMemory",
|
|
5271
|
+
memoryId: request.payload.memory_id
|
|
5272
|
+
});
|
|
5273
|
+
return JSON.stringify(
|
|
5274
|
+
{
|
|
5275
|
+
success: false,
|
|
5276
|
+
error: "Memory not found",
|
|
5277
|
+
message: `Original memory ${request.payload.memory_id} no longer exists`
|
|
5278
|
+
},
|
|
5279
|
+
null,
|
|
5280
|
+
2
|
|
5281
|
+
);
|
|
5282
|
+
}
|
|
5283
|
+
if (originalMemory.properties.user_id !== userId) {
|
|
5284
|
+
logger.warn("Permission denied - wrong owner", {
|
|
5285
|
+
function: "executePublishMemory",
|
|
5286
|
+
memoryId: request.payload.memory_id,
|
|
5287
|
+
memoryOwner: originalMemory.properties.user_id,
|
|
5288
|
+
requestingUser: userId
|
|
5289
|
+
});
|
|
5290
|
+
return JSON.stringify(
|
|
5291
|
+
{
|
|
5292
|
+
success: false,
|
|
5293
|
+
error: "Permission denied",
|
|
5294
|
+
message: "You can only publish your own memories"
|
|
5295
|
+
},
|
|
5296
|
+
null,
|
|
5297
|
+
2
|
|
5298
|
+
);
|
|
5299
|
+
}
|
|
5300
|
+
const compositeId = generateCompositeId(userId, request.payload.memory_id);
|
|
5301
|
+
logger.debug("Generated composite ID", {
|
|
5302
|
+
function: "executePublishMemory",
|
|
5303
|
+
compositeId,
|
|
5304
|
+
userId,
|
|
5305
|
+
memoryId: request.payload.memory_id
|
|
5306
|
+
});
|
|
5307
|
+
const existingSpaceIds = Array.isArray(originalMemory.properties.space_ids) ? originalMemory.properties.space_ids : [];
|
|
5308
|
+
const existingGroupIds = Array.isArray(originalMemory.properties.group_ids) ? originalMemory.properties.group_ids : [];
|
|
5309
|
+
const originalTags = Array.isArray(originalMemory.properties.tags) ? originalMemory.properties.tags : [];
|
|
5310
|
+
const additionalTags = Array.isArray(request.payload.additional_tags) ? request.payload.additional_tags : [];
|
|
5311
|
+
const mergedTags = [...originalTags, ...additionalTags];
|
|
5312
|
+
const publicationResults = { groups: [] };
|
|
5313
|
+
if (spaces.length > 0) {
|
|
5314
|
+
logger.debug("Ensuring public spaces collection exists", {
|
|
5315
|
+
function: "executePublishMemory"
|
|
5316
|
+
});
|
|
5317
|
+
const publicCollection = await ensurePublicCollection(weaviateClient);
|
|
5318
|
+
let existingSpaceMemory = null;
|
|
5319
|
+
try {
|
|
5320
|
+
existingSpaceMemory = await fetchMemoryWithAllProperties(publicCollection, compositeId);
|
|
5321
|
+
} catch (e) {
|
|
5322
|
+
}
|
|
5323
|
+
const newSpaceIds = [.../* @__PURE__ */ new Set([...existingSpaceIds, ...spaces])];
|
|
5324
|
+
let spaceModerationStatus = "approved";
|
|
5325
|
+
for (const spaceId of spaces) {
|
|
5326
|
+
const spaceConfig = await getSpaceConfig(spaceId, "space");
|
|
5327
|
+
if (spaceConfig.require_moderation) {
|
|
5328
|
+
spaceModerationStatus = "pending";
|
|
5329
|
+
break;
|
|
5330
|
+
}
|
|
5331
|
+
}
|
|
5332
|
+
const publishedMemory = {
|
|
5333
|
+
...originalMemory.properties,
|
|
5334
|
+
// Use composite ID as the document ID
|
|
5335
|
+
id: compositeId,
|
|
5336
|
+
// Tracking arrays (v2 feature)
|
|
5337
|
+
space_ids: newSpaceIds,
|
|
5338
|
+
group_ids: existingGroupIds,
|
|
5339
|
+
// Legacy compatibility
|
|
5340
|
+
spaces,
|
|
5341
|
+
// Publication metadata
|
|
5342
|
+
author_id: userId,
|
|
5343
|
+
published_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5344
|
+
discovery_count: 0,
|
|
5345
|
+
attribution: "user",
|
|
5346
|
+
// Moderation status
|
|
5347
|
+
moderation_status: spaceModerationStatus,
|
|
5348
|
+
// Merge tags
|
|
5349
|
+
tags: mergedTags
|
|
5350
|
+
};
|
|
5351
|
+
delete publishedMemory._additional;
|
|
5352
|
+
logger.info("Publishing memory to Memory_spaces_public", {
|
|
5353
|
+
function: "executePublishMemory",
|
|
5354
|
+
compositeId,
|
|
5355
|
+
spaces,
|
|
5356
|
+
spaceIds: newSpaceIds
|
|
5357
|
+
});
|
|
5358
|
+
try {
|
|
5359
|
+
if (existingSpaceMemory) {
|
|
5360
|
+
await publicCollection.data.update({
|
|
5361
|
+
id: compositeId,
|
|
5362
|
+
properties: publishedMemory
|
|
5363
|
+
});
|
|
5364
|
+
publicationResults.spaces = { success: true, id: compositeId };
|
|
5365
|
+
} else {
|
|
5366
|
+
await publicCollection.data.insert({
|
|
5367
|
+
id: compositeId,
|
|
5368
|
+
properties: publishedMemory
|
|
5369
|
+
});
|
|
5370
|
+
publicationResults.spaces = { success: true, id: compositeId };
|
|
5371
|
+
}
|
|
5372
|
+
logger.info("Memory published to spaces successfully", {
|
|
5373
|
+
function: "executePublishMemory",
|
|
5374
|
+
compositeId,
|
|
5375
|
+
spaces
|
|
5376
|
+
});
|
|
5377
|
+
} catch (spaceError) {
|
|
5378
|
+
logger.error("Failed to publish to spaces", {
|
|
5379
|
+
function: "executePublishMemory",
|
|
5380
|
+
error: spaceError instanceof Error ? spaceError.message : String(spaceError)
|
|
5381
|
+
});
|
|
5382
|
+
publicationResults.spaces = {
|
|
5383
|
+
success: false,
|
|
5384
|
+
error: spaceError instanceof Error ? spaceError.message : String(spaceError)
|
|
5385
|
+
};
|
|
5386
|
+
}
|
|
5387
|
+
}
|
|
5388
|
+
for (const groupId of groups) {
|
|
5389
|
+
const groupCollectionName = getCollectionName("GROUPS" /* GROUPS */, groupId);
|
|
5390
|
+
logger.debug("Publishing to group collection", {
|
|
5391
|
+
function: "executePublishMemory",
|
|
5392
|
+
groupId,
|
|
5393
|
+
collectionName: groupCollectionName
|
|
5394
|
+
});
|
|
5395
|
+
try {
|
|
5396
|
+
const groupCollection = weaviateClient.collections.get(groupCollectionName);
|
|
5397
|
+
let existingGroupMemory = null;
|
|
5398
|
+
try {
|
|
5399
|
+
existingGroupMemory = await fetchMemoryWithAllProperties(groupCollection, compositeId);
|
|
5400
|
+
} catch (e) {
|
|
5401
|
+
}
|
|
5402
|
+
const newGroupIds = [.../* @__PURE__ */ new Set([...existingGroupIds, groupId])];
|
|
5403
|
+
const groupConfig = await getSpaceConfig(groupId, "group");
|
|
5404
|
+
const groupModerationStatus = groupConfig.require_moderation ? "pending" : "approved";
|
|
5405
|
+
const groupMemory = {
|
|
5406
|
+
...originalMemory.properties,
|
|
5407
|
+
// Use composite ID
|
|
5408
|
+
id: compositeId,
|
|
5409
|
+
// Tracking arrays
|
|
5410
|
+
space_ids: existingSpaceIds,
|
|
5411
|
+
group_ids: newGroupIds,
|
|
5412
|
+
// Publication metadata
|
|
5413
|
+
author_id: userId,
|
|
5414
|
+
published_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5415
|
+
discovery_count: 0,
|
|
5416
|
+
attribution: "user",
|
|
5417
|
+
// Moderation status
|
|
5418
|
+
moderation_status: groupModerationStatus,
|
|
5419
|
+
// Merge tags
|
|
5420
|
+
tags: mergedTags
|
|
5421
|
+
};
|
|
5422
|
+
delete groupMemory._additional;
|
|
5423
|
+
if (existingGroupMemory) {
|
|
5424
|
+
await groupCollection.data.update({
|
|
5425
|
+
id: compositeId,
|
|
5426
|
+
properties: groupMemory
|
|
5427
|
+
});
|
|
5428
|
+
} else {
|
|
5429
|
+
await groupCollection.data.insert({
|
|
5430
|
+
id: compositeId,
|
|
5431
|
+
properties: groupMemory
|
|
5432
|
+
});
|
|
5433
|
+
}
|
|
5434
|
+
publicationResults.groups.push({ groupId, success: true, id: compositeId });
|
|
5435
|
+
logger.info("Memory published to group successfully", {
|
|
5436
|
+
function: "executePublishMemory",
|
|
5437
|
+
compositeId,
|
|
5438
|
+
groupId
|
|
5439
|
+
});
|
|
5440
|
+
} catch (groupError) {
|
|
5441
|
+
logger.error("Failed to publish to group", {
|
|
5442
|
+
function: "executePublishMemory",
|
|
5443
|
+
groupId,
|
|
5444
|
+
error: groupError instanceof Error ? groupError.message : String(groupError)
|
|
5445
|
+
});
|
|
5446
|
+
publicationResults.groups.push({
|
|
5447
|
+
groupId,
|
|
5448
|
+
success: false,
|
|
5449
|
+
error: groupError instanceof Error ? groupError.message : String(groupError)
|
|
5450
|
+
});
|
|
5451
|
+
}
|
|
5452
|
+
}
|
|
5453
|
+
const finalSpaceIds = publicationResults.spaces?.success ? [.../* @__PURE__ */ new Set([...existingSpaceIds, ...spaces])] : existingSpaceIds;
|
|
5454
|
+
const successfulGroups = publicationResults.groups.filter((g) => g.success).map((g) => g.groupId);
|
|
5455
|
+
const finalGroupIds = [.../* @__PURE__ */ new Set([...existingGroupIds, ...successfulGroups])];
|
|
5456
|
+
if (finalSpaceIds.length > existingSpaceIds.length || finalGroupIds.length > existingGroupIds.length) {
|
|
5457
|
+
try {
|
|
5458
|
+
await userCollection.data.update({
|
|
5459
|
+
id: request.payload.memory_id,
|
|
5460
|
+
properties: {
|
|
5461
|
+
space_ids: finalSpaceIds,
|
|
5462
|
+
group_ids: finalGroupIds
|
|
5463
|
+
}
|
|
5464
|
+
});
|
|
5465
|
+
logger.info("Updated source memory with tracking arrays", {
|
|
5466
|
+
function: "executePublishMemory",
|
|
5467
|
+
memoryId: request.payload.memory_id,
|
|
5468
|
+
spaceIds: finalSpaceIds,
|
|
5469
|
+
groupIds: finalGroupIds
|
|
5470
|
+
});
|
|
5471
|
+
} catch (updateError) {
|
|
5472
|
+
logger.warn("Failed to update source memory tracking arrays", {
|
|
5473
|
+
function: "executePublishMemory",
|
|
5474
|
+
memoryId: request.payload.memory_id,
|
|
5475
|
+
error: updateError instanceof Error ? updateError.message : String(updateError)
|
|
5476
|
+
});
|
|
5477
|
+
}
|
|
5478
|
+
}
|
|
5479
|
+
const successfulPublications = [];
|
|
5480
|
+
const failedPublications = [];
|
|
5481
|
+
if (spaces.length > 0) {
|
|
5482
|
+
if (publicationResults.spaces?.success) {
|
|
5483
|
+
successfulPublications.push(`spaces: ${spaces.join(", ")}`);
|
|
5484
|
+
} else {
|
|
5485
|
+
failedPublications.push(`spaces: ${publicationResults.spaces?.error || "unknown error"}`);
|
|
5486
|
+
}
|
|
5487
|
+
}
|
|
5488
|
+
for (const groupResult of publicationResults.groups) {
|
|
5489
|
+
if (groupResult.success) {
|
|
5490
|
+
successfulPublications.push(`group: ${groupResult.groupId}`);
|
|
5491
|
+
} else {
|
|
5492
|
+
failedPublications.push(`group ${groupResult.groupId}: ${groupResult.error || "unknown error"}`);
|
|
5493
|
+
}
|
|
5494
|
+
}
|
|
5495
|
+
if (successfulPublications.length > 0) {
|
|
5496
|
+
return JSON.stringify(
|
|
5497
|
+
{
|
|
5498
|
+
success: true,
|
|
5499
|
+
composite_id: compositeId,
|
|
5500
|
+
published_to: successfulPublications,
|
|
5501
|
+
failed: failedPublications.length > 0 ? failedPublications : void 0,
|
|
5502
|
+
space_ids: finalSpaceIds,
|
|
5503
|
+
group_ids: finalGroupIds
|
|
5504
|
+
},
|
|
5505
|
+
null,
|
|
5506
|
+
2
|
|
5507
|
+
);
|
|
5508
|
+
} else {
|
|
5509
|
+
return JSON.stringify(
|
|
5510
|
+
{
|
|
5511
|
+
success: false,
|
|
5512
|
+
error: "Publication failed",
|
|
5513
|
+
message: "Failed to publish to any destination",
|
|
5514
|
+
details: failedPublications
|
|
5515
|
+
},
|
|
5516
|
+
null,
|
|
5517
|
+
2
|
|
5518
|
+
);
|
|
5519
|
+
}
|
|
5520
|
+
} catch (error) {
|
|
5521
|
+
debug.error("Execute publish failed", {
|
|
5522
|
+
error: error instanceof Error ? error.message : String(error),
|
|
5523
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
5524
|
+
});
|
|
5525
|
+
handleToolError(error, {
|
|
5526
|
+
toolName: "remember_confirm",
|
|
5527
|
+
userId,
|
|
5528
|
+
operation: "execute publish_memory",
|
|
5529
|
+
action: "publish_memory"
|
|
5530
|
+
});
|
|
5531
|
+
}
|
|
5532
|
+
}
|
|
5533
|
+
async function executeDeleteMemory(request, userId, authContext) {
|
|
5534
|
+
try {
|
|
5535
|
+
logger.info("Executing delete memory action", {
|
|
5536
|
+
function: "executeDeleteMemory",
|
|
5537
|
+
userId,
|
|
5538
|
+
memoryId: request.payload.memory_id,
|
|
4755
5539
|
hasReason: !!request.payload.reason
|
|
4756
5540
|
});
|
|
4757
5541
|
const { memory_id, reason } = request.payload;
|
|
4758
5542
|
const client2 = getWeaviateClient();
|
|
4759
|
-
const collectionName =
|
|
5543
|
+
const collectionName = getMemoryCollectionName(userId);
|
|
4760
5544
|
const collection = client2.collections.get(collectionName);
|
|
4761
5545
|
await collection.data.update({
|
|
4762
5546
|
id: memory_id,
|
|
@@ -4792,6 +5576,405 @@ async function executeDeleteMemory(request, userId) {
|
|
|
4792
5576
|
throw error;
|
|
4793
5577
|
}
|
|
4794
5578
|
}
|
|
5579
|
+
async function executeRetractMemory(request, userId, authContext) {
|
|
5580
|
+
const debug = createDebugLogger({
|
|
5581
|
+
tool: "remember_confirm",
|
|
5582
|
+
userId,
|
|
5583
|
+
operation: "execute_retract"
|
|
5584
|
+
});
|
|
5585
|
+
try {
|
|
5586
|
+
const spaces = request.payload.spaces || [];
|
|
5587
|
+
const groups = request.payload.groups || [];
|
|
5588
|
+
debug.debug("Executing retract memory action", {
|
|
5589
|
+
memoryId: request.payload.memory_id,
|
|
5590
|
+
spaces,
|
|
5591
|
+
groups
|
|
5592
|
+
});
|
|
5593
|
+
logger.info("Executing retract memory action", {
|
|
5594
|
+
function: "executeRetractMemory",
|
|
5595
|
+
userId,
|
|
5596
|
+
memoryId: request.payload.memory_id,
|
|
5597
|
+
spaces,
|
|
5598
|
+
groups,
|
|
5599
|
+
spaceCount: spaces.length,
|
|
5600
|
+
groupCount: groups.length
|
|
5601
|
+
});
|
|
5602
|
+
const weaviateClient = getWeaviateClient();
|
|
5603
|
+
const userCollectionName = getMemoryCollectionName(userId);
|
|
5604
|
+
const userCollection = weaviateClient.collections.get(userCollectionName);
|
|
5605
|
+
const sourceMemory = await fetchMemoryWithAllProperties(
|
|
5606
|
+
userCollection,
|
|
5607
|
+
request.payload.memory_id
|
|
5608
|
+
);
|
|
5609
|
+
if (!sourceMemory) {
|
|
5610
|
+
logger.info("Source memory not found for retraction", {
|
|
5611
|
+
function: "executeRetractMemory",
|
|
5612
|
+
memoryId: request.payload.memory_id
|
|
5613
|
+
});
|
|
5614
|
+
return JSON.stringify(
|
|
5615
|
+
{
|
|
5616
|
+
success: false,
|
|
5617
|
+
error: "Memory not found",
|
|
5618
|
+
message: `Source memory ${request.payload.memory_id} no longer exists`
|
|
5619
|
+
},
|
|
5620
|
+
null,
|
|
5621
|
+
2
|
|
5622
|
+
);
|
|
5623
|
+
}
|
|
5624
|
+
const currentSpaceIds = Array.isArray(sourceMemory.properties.space_ids) ? sourceMemory.properties.space_ids : [];
|
|
5625
|
+
const currentGroupIds = Array.isArray(sourceMemory.properties.group_ids) ? sourceMemory.properties.group_ids : [];
|
|
5626
|
+
const compositeId = generateCompositeId(userId, request.payload.memory_id);
|
|
5627
|
+
const retractionResults = { groups: [] };
|
|
5628
|
+
if (spaces.length > 0) {
|
|
5629
|
+
try {
|
|
5630
|
+
const publicCollection = weaviateClient.collections.get(
|
|
5631
|
+
getCollectionName("SPACES" /* SPACES */)
|
|
5632
|
+
);
|
|
5633
|
+
const publishedMemory = await fetchMemoryWithAllProperties(publicCollection, compositeId);
|
|
5634
|
+
if (publishedMemory) {
|
|
5635
|
+
const newSpaceIds = currentSpaceIds.filter((id) => !spaces.includes(id));
|
|
5636
|
+
await publicCollection.data.update({
|
|
5637
|
+
id: compositeId,
|
|
5638
|
+
properties: {
|
|
5639
|
+
space_ids: newSpaceIds,
|
|
5640
|
+
retracted_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
5641
|
+
}
|
|
5642
|
+
});
|
|
5643
|
+
retractionResults.spaces = { success: true };
|
|
5644
|
+
logger.info("Memory retracted from spaces (orphaned)", {
|
|
5645
|
+
function: "executeRetractMemory",
|
|
5646
|
+
compositeId,
|
|
5647
|
+
retractedSpaces: spaces,
|
|
5648
|
+
remainingSpaces: newSpaceIds,
|
|
5649
|
+
isOrphaned: newSpaceIds.length === 0 && currentGroupIds.length === 0
|
|
5650
|
+
});
|
|
5651
|
+
} else {
|
|
5652
|
+
retractionResults.spaces = {
|
|
5653
|
+
success: false,
|
|
5654
|
+
error: "Memory not found in spaces collection"
|
|
5655
|
+
};
|
|
5656
|
+
logger.warn("Memory not found in spaces collection", {
|
|
5657
|
+
function: "executeRetractMemory",
|
|
5658
|
+
compositeId
|
|
5659
|
+
});
|
|
5660
|
+
}
|
|
5661
|
+
} catch (spaceError) {
|
|
5662
|
+
logger.error("Failed to retract from spaces", {
|
|
5663
|
+
function: "executeRetractMemory",
|
|
5664
|
+
error: spaceError instanceof Error ? spaceError.message : String(spaceError)
|
|
5665
|
+
});
|
|
5666
|
+
retractionResults.spaces = {
|
|
5667
|
+
success: false,
|
|
5668
|
+
error: spaceError instanceof Error ? spaceError.message : String(spaceError)
|
|
5669
|
+
};
|
|
5670
|
+
}
|
|
5671
|
+
}
|
|
5672
|
+
for (const groupId of groups) {
|
|
5673
|
+
const groupCollectionName = getCollectionName("GROUPS" /* GROUPS */, groupId);
|
|
5674
|
+
try {
|
|
5675
|
+
const groupCollection = weaviateClient.collections.get(groupCollectionName);
|
|
5676
|
+
const groupMemory = await fetchMemoryWithAllProperties(groupCollection, compositeId);
|
|
5677
|
+
if (groupMemory) {
|
|
5678
|
+
const groupMemoryGroupIds = Array.isArray(groupMemory.properties.group_ids) ? groupMemory.properties.group_ids : [];
|
|
5679
|
+
const newGroupIds = groupMemoryGroupIds.filter((id) => id !== groupId);
|
|
5680
|
+
await groupCollection.data.update({
|
|
5681
|
+
id: compositeId,
|
|
5682
|
+
properties: {
|
|
5683
|
+
group_ids: newGroupIds,
|
|
5684
|
+
retracted_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
5685
|
+
}
|
|
5686
|
+
});
|
|
5687
|
+
retractionResults.groups.push({ groupId, success: true });
|
|
5688
|
+
logger.info("Memory retracted from group (orphaned)", {
|
|
5689
|
+
function: "executeRetractMemory",
|
|
5690
|
+
compositeId,
|
|
5691
|
+
groupId,
|
|
5692
|
+
remainingGroups: newGroupIds,
|
|
5693
|
+
isOrphaned: newGroupIds.length === 0
|
|
5694
|
+
});
|
|
5695
|
+
} else {
|
|
5696
|
+
retractionResults.groups.push({
|
|
5697
|
+
groupId,
|
|
5698
|
+
success: false,
|
|
5699
|
+
error: "Memory not found in group"
|
|
5700
|
+
});
|
|
5701
|
+
logger.warn("Memory not found in group collection", {
|
|
5702
|
+
function: "executeRetractMemory",
|
|
5703
|
+
compositeId,
|
|
5704
|
+
groupId
|
|
5705
|
+
});
|
|
5706
|
+
}
|
|
5707
|
+
} catch (groupError) {
|
|
5708
|
+
logger.error("Failed to retract from group", {
|
|
5709
|
+
function: "executeRetractMemory",
|
|
5710
|
+
groupId,
|
|
5711
|
+
error: groupError instanceof Error ? groupError.message : String(groupError)
|
|
5712
|
+
});
|
|
5713
|
+
retractionResults.groups.push({
|
|
5714
|
+
groupId,
|
|
5715
|
+
success: false,
|
|
5716
|
+
error: groupError instanceof Error ? groupError.message : String(groupError)
|
|
5717
|
+
});
|
|
5718
|
+
}
|
|
5719
|
+
}
|
|
5720
|
+
const finalSpaceIds = retractionResults.spaces?.success ? currentSpaceIds.filter((id) => !spaces.includes(id)) : currentSpaceIds;
|
|
5721
|
+
const successfulGroupRetractions = retractionResults.groups.filter((g) => g.success).map((g) => g.groupId);
|
|
5722
|
+
const finalGroupIds = currentGroupIds.filter((id) => !successfulGroupRetractions.includes(id));
|
|
5723
|
+
try {
|
|
5724
|
+
await userCollection.data.update({
|
|
5725
|
+
id: request.payload.memory_id,
|
|
5726
|
+
properties: {
|
|
5727
|
+
space_ids: finalSpaceIds,
|
|
5728
|
+
group_ids: finalGroupIds
|
|
5729
|
+
}
|
|
5730
|
+
});
|
|
5731
|
+
logger.info("Updated source memory tracking arrays after retraction", {
|
|
5732
|
+
function: "executeRetractMemory",
|
|
5733
|
+
memoryId: request.payload.memory_id,
|
|
5734
|
+
spaceIds: finalSpaceIds,
|
|
5735
|
+
groupIds: finalGroupIds
|
|
5736
|
+
});
|
|
5737
|
+
} catch (updateError) {
|
|
5738
|
+
logger.warn("Failed to update source memory tracking arrays after retraction", {
|
|
5739
|
+
function: "executeRetractMemory",
|
|
5740
|
+
memoryId: request.payload.memory_id,
|
|
5741
|
+
error: updateError instanceof Error ? updateError.message : String(updateError)
|
|
5742
|
+
});
|
|
5743
|
+
}
|
|
5744
|
+
const successfulRetractions = [];
|
|
5745
|
+
const failedRetractions = [];
|
|
5746
|
+
if (spaces.length > 0) {
|
|
5747
|
+
if (retractionResults.spaces?.success) {
|
|
5748
|
+
successfulRetractions.push(`spaces: ${spaces.join(", ")}`);
|
|
5749
|
+
} else {
|
|
5750
|
+
failedRetractions.push(`spaces: ${retractionResults.spaces?.error || "unknown error"}`);
|
|
5751
|
+
}
|
|
5752
|
+
}
|
|
5753
|
+
for (const groupResult of retractionResults.groups) {
|
|
5754
|
+
if (groupResult.success) {
|
|
5755
|
+
successfulRetractions.push(`group: ${groupResult.groupId}`);
|
|
5756
|
+
} else {
|
|
5757
|
+
failedRetractions.push(`group ${groupResult.groupId}: ${groupResult.error || "unknown error"}`);
|
|
5758
|
+
}
|
|
5759
|
+
}
|
|
5760
|
+
if (successfulRetractions.length > 0) {
|
|
5761
|
+
return JSON.stringify(
|
|
5762
|
+
{
|
|
5763
|
+
success: true,
|
|
5764
|
+
composite_id: compositeId,
|
|
5765
|
+
retracted_from: successfulRetractions,
|
|
5766
|
+
failed: failedRetractions.length > 0 ? failedRetractions : void 0,
|
|
5767
|
+
space_ids: finalSpaceIds,
|
|
5768
|
+
group_ids: finalGroupIds,
|
|
5769
|
+
is_orphaned: finalSpaceIds.length === 0 && finalGroupIds.length === 0
|
|
5770
|
+
},
|
|
5771
|
+
null,
|
|
5772
|
+
2
|
|
5773
|
+
);
|
|
5774
|
+
} else {
|
|
5775
|
+
return JSON.stringify(
|
|
5776
|
+
{
|
|
5777
|
+
success: false,
|
|
5778
|
+
error: "Retraction failed",
|
|
5779
|
+
message: "Failed to retract from any destination",
|
|
5780
|
+
details: failedRetractions
|
|
5781
|
+
},
|
|
5782
|
+
null,
|
|
5783
|
+
2
|
|
5784
|
+
);
|
|
5785
|
+
}
|
|
5786
|
+
} catch (error) {
|
|
5787
|
+
debug.error("Execute retract failed", {
|
|
5788
|
+
error: error instanceof Error ? error.message : String(error),
|
|
5789
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
5790
|
+
});
|
|
5791
|
+
handleToolError(error, {
|
|
5792
|
+
toolName: "remember_confirm",
|
|
5793
|
+
userId,
|
|
5794
|
+
operation: "execute retract_memory",
|
|
5795
|
+
action: "retract_memory"
|
|
5796
|
+
});
|
|
5797
|
+
}
|
|
5798
|
+
}
|
|
5799
|
+
async function executeReviseMemory(request, userId, authContext) {
|
|
5800
|
+
const debug = createDebugLogger({
|
|
5801
|
+
tool: "remember_confirm",
|
|
5802
|
+
userId,
|
|
5803
|
+
operation: "execute_revise"
|
|
5804
|
+
});
|
|
5805
|
+
try {
|
|
5806
|
+
const { memory_id, space_ids = [], group_ids = [] } = request.payload;
|
|
5807
|
+
debug.debug("Executing revise memory action", {
|
|
5808
|
+
memoryId: memory_id,
|
|
5809
|
+
spaceIds: space_ids,
|
|
5810
|
+
groupIds: group_ids
|
|
5811
|
+
});
|
|
5812
|
+
logger.info("Executing revise memory action", {
|
|
5813
|
+
function: "executeReviseMemory",
|
|
5814
|
+
userId,
|
|
5815
|
+
memoryId: memory_id,
|
|
5816
|
+
spaceCount: space_ids.length,
|
|
5817
|
+
groupCount: group_ids.length
|
|
5818
|
+
});
|
|
5819
|
+
const weaviateClient = getWeaviateClient();
|
|
5820
|
+
const userCollectionName = getMemoryCollectionName(userId);
|
|
5821
|
+
const userCollection = weaviateClient.collections.get(userCollectionName);
|
|
5822
|
+
const sourceMemory = await fetchMemoryWithAllProperties(
|
|
5823
|
+
userCollection,
|
|
5824
|
+
memory_id
|
|
5825
|
+
);
|
|
5826
|
+
if (!sourceMemory) {
|
|
5827
|
+
return JSON.stringify(
|
|
5828
|
+
{
|
|
5829
|
+
success: false,
|
|
5830
|
+
error: "Memory not found",
|
|
5831
|
+
message: `Source memory ${memory_id} no longer exists`
|
|
5832
|
+
},
|
|
5833
|
+
null,
|
|
5834
|
+
2
|
|
5835
|
+
);
|
|
5836
|
+
}
|
|
5837
|
+
if (sourceMemory.properties.user_id !== userId) {
|
|
5838
|
+
return JSON.stringify(
|
|
5839
|
+
{
|
|
5840
|
+
success: false,
|
|
5841
|
+
error: "Permission denied",
|
|
5842
|
+
message: "You can only revise your own memories"
|
|
5843
|
+
},
|
|
5844
|
+
null,
|
|
5845
|
+
2
|
|
5846
|
+
);
|
|
5847
|
+
}
|
|
5848
|
+
const newContent = String(sourceMemory.properties.content ?? "");
|
|
5849
|
+
const revisedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5850
|
+
const compositeId = generateCompositeId(userId, memory_id);
|
|
5851
|
+
const results = [];
|
|
5852
|
+
logger.info("Revising published copies", {
|
|
5853
|
+
function: "executeReviseMemory",
|
|
5854
|
+
compositeId,
|
|
5855
|
+
spaceCount: space_ids.length > 0 ? 1 : 0,
|
|
5856
|
+
groupCount: group_ids.length
|
|
5857
|
+
});
|
|
5858
|
+
async function reviseInCollection(collectionName, locationLabel) {
|
|
5859
|
+
try {
|
|
5860
|
+
const collection = weaviateClient.collections.get(collectionName);
|
|
5861
|
+
const publishedMemory = await fetchMemoryWithAllProperties(
|
|
5862
|
+
collection,
|
|
5863
|
+
compositeId
|
|
5864
|
+
);
|
|
5865
|
+
if (!publishedMemory) {
|
|
5866
|
+
results.push({
|
|
5867
|
+
location: locationLabel,
|
|
5868
|
+
status: "skipped",
|
|
5869
|
+
error: "Published copy not found (may have been deleted)"
|
|
5870
|
+
});
|
|
5871
|
+
logger.warn("Published copy not found in collection", {
|
|
5872
|
+
function: "executeReviseMemory",
|
|
5873
|
+
collectionName,
|
|
5874
|
+
compositeId
|
|
5875
|
+
});
|
|
5876
|
+
return;
|
|
5877
|
+
}
|
|
5878
|
+
const oldContent = String(publishedMemory.properties.content ?? "");
|
|
5879
|
+
let revisionHistory = parseRevisionHistory(
|
|
5880
|
+
publishedMemory.properties.revision_history
|
|
5881
|
+
);
|
|
5882
|
+
if (oldContent !== newContent) {
|
|
5883
|
+
revisionHistory = buildRevisionHistory(
|
|
5884
|
+
revisionHistory,
|
|
5885
|
+
oldContent,
|
|
5886
|
+
revisedAt
|
|
5887
|
+
);
|
|
5888
|
+
}
|
|
5889
|
+
const currentRevisionCount = typeof publishedMemory.properties.revision_count === "number" ? publishedMemory.properties.revision_count : 0;
|
|
5890
|
+
await collection.data.update({
|
|
5891
|
+
id: compositeId,
|
|
5892
|
+
properties: {
|
|
5893
|
+
content: newContent,
|
|
5894
|
+
revised_at: revisedAt,
|
|
5895
|
+
revision_count: currentRevisionCount + 1,
|
|
5896
|
+
revision_history: JSON.stringify(revisionHistory)
|
|
5897
|
+
}
|
|
5898
|
+
});
|
|
5899
|
+
results.push({ location: locationLabel, status: "success" });
|
|
5900
|
+
logger.info("Revised published memory in collection", {
|
|
5901
|
+
function: "executeReviseMemory",
|
|
5902
|
+
collectionName,
|
|
5903
|
+
compositeId,
|
|
5904
|
+
revisionCount: currentRevisionCount + 1,
|
|
5905
|
+
contentChanged: oldContent !== newContent
|
|
5906
|
+
});
|
|
5907
|
+
} catch (err) {
|
|
5908
|
+
results.push({
|
|
5909
|
+
location: locationLabel,
|
|
5910
|
+
status: "failed",
|
|
5911
|
+
error: err instanceof Error ? err.message : String(err)
|
|
5912
|
+
});
|
|
5913
|
+
logger.error("Failed to revise in collection", {
|
|
5914
|
+
function: "executeReviseMemory",
|
|
5915
|
+
collectionName,
|
|
5916
|
+
compositeId,
|
|
5917
|
+
error: err instanceof Error ? err.message : String(err)
|
|
5918
|
+
});
|
|
5919
|
+
}
|
|
5920
|
+
}
|
|
5921
|
+
if (space_ids.length > 0) {
|
|
5922
|
+
await reviseInCollection(
|
|
5923
|
+
getCollectionName("SPACES" /* SPACES */),
|
|
5924
|
+
"Memory_spaces_public"
|
|
5925
|
+
);
|
|
5926
|
+
}
|
|
5927
|
+
for (const groupId of group_ids) {
|
|
5928
|
+
await reviseInCollection(
|
|
5929
|
+
getCollectionName("GROUPS" /* GROUPS */, groupId),
|
|
5930
|
+
`Memory_groups_${groupId}`
|
|
5931
|
+
);
|
|
5932
|
+
}
|
|
5933
|
+
const successCount = results.filter((r) => r.status === "success").length;
|
|
5934
|
+
const failedCount = results.filter((r) => r.status === "failed").length;
|
|
5935
|
+
const skippedCount = results.filter((r) => r.status === "skipped").length;
|
|
5936
|
+
logger.info("Revise execution complete", {
|
|
5937
|
+
function: "executeReviseMemory",
|
|
5938
|
+
userId,
|
|
5939
|
+
memoryId: memory_id,
|
|
5940
|
+
successCount,
|
|
5941
|
+
failedCount,
|
|
5942
|
+
skippedCount
|
|
5943
|
+
});
|
|
5944
|
+
return JSON.stringify(
|
|
5945
|
+
{
|
|
5946
|
+
success: successCount > 0,
|
|
5947
|
+
composite_id: compositeId,
|
|
5948
|
+
revised_at: revisedAt,
|
|
5949
|
+
summary: {
|
|
5950
|
+
total: results.length,
|
|
5951
|
+
success: successCount,
|
|
5952
|
+
failed: failedCount,
|
|
5953
|
+
skipped: skippedCount
|
|
5954
|
+
},
|
|
5955
|
+
results,
|
|
5956
|
+
...failedCount > 0 ? {
|
|
5957
|
+
warnings: [
|
|
5958
|
+
`Failed to revise ${failedCount} of ${results.length} location(s)`
|
|
5959
|
+
]
|
|
5960
|
+
} : {}
|
|
5961
|
+
},
|
|
5962
|
+
null,
|
|
5963
|
+
2
|
|
5964
|
+
);
|
|
5965
|
+
} catch (error) {
|
|
5966
|
+
debug.error("Execute revise failed", {
|
|
5967
|
+
error: error instanceof Error ? error.message : String(error),
|
|
5968
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
5969
|
+
});
|
|
5970
|
+
handleToolError(error, {
|
|
5971
|
+
toolName: "remember_confirm",
|
|
5972
|
+
userId,
|
|
5973
|
+
operation: "execute revise_memory",
|
|
5974
|
+
action: "revise_memory"
|
|
5975
|
+
});
|
|
5976
|
+
}
|
|
5977
|
+
}
|
|
4795
5978
|
|
|
4796
5979
|
// src/tools/deny.ts
|
|
4797
5980
|
var denyTool = {
|
|
@@ -4818,8 +6001,11 @@ This ensures proper user consent workflow is followed.`,
|
|
|
4818
6001
|
required: ["token"]
|
|
4819
6002
|
}
|
|
4820
6003
|
};
|
|
4821
|
-
async function handleDeny(args, userId) {
|
|
6004
|
+
async function handleDeny(args, userId, authContext) {
|
|
6005
|
+
const debug = createDebugLogger({ tool: "remember_deny", userId, operation: "deny action" });
|
|
4822
6006
|
try {
|
|
6007
|
+
debug.info("Tool invoked");
|
|
6008
|
+
debug.trace("Arguments", { args });
|
|
4823
6009
|
const success = await confirmationTokenService.denyRequest(userId, args.token);
|
|
4824
6010
|
if (!success) {
|
|
4825
6011
|
return JSON.stringify(
|
|
@@ -4840,6 +6026,7 @@ async function handleDeny(args, userId) {
|
|
|
4840
6026
|
2
|
|
4841
6027
|
);
|
|
4842
6028
|
} catch (error) {
|
|
6029
|
+
debug.error("Tool failed", { error: error instanceof Error ? error.message : String(error) });
|
|
4843
6030
|
handleToolError(error, {
|
|
4844
6031
|
toolName: "remember_deny",
|
|
4845
6032
|
userId,
|
|
@@ -4852,9 +6039,32 @@ async function handleDeny(args, userId) {
|
|
|
4852
6039
|
// src/tools/search-space.ts
|
|
4853
6040
|
import { Filters as Filters4 } from "weaviate-client";
|
|
4854
6041
|
init_space_memory();
|
|
6042
|
+
init_logger();
|
|
6043
|
+
|
|
6044
|
+
// src/utils/auth-helpers.ts
|
|
6045
|
+
function canModerate(authContext, groupId) {
|
|
6046
|
+
if (!authContext?.credentials)
|
|
6047
|
+
return false;
|
|
6048
|
+
const membership = authContext.credentials.group_memberships.find((m) => m.group_id === groupId);
|
|
6049
|
+
return membership?.permissions.can_moderate ?? false;
|
|
6050
|
+
}
|
|
6051
|
+
function canModerateAny(authContext) {
|
|
6052
|
+
if (!authContext?.credentials)
|
|
6053
|
+
return false;
|
|
6054
|
+
return authContext.credentials.group_memberships.some((m) => m.permissions.can_moderate);
|
|
6055
|
+
}
|
|
6056
|
+
|
|
6057
|
+
// src/tools/search-space.ts
|
|
4855
6058
|
var searchSpaceTool = {
|
|
4856
6059
|
name: "remember_search_space",
|
|
4857
|
-
description: `Search
|
|
6060
|
+
description: `Search shared spaces and/or groups to discover memories from other users.
|
|
6061
|
+
|
|
6062
|
+
Destinations:
|
|
6063
|
+
- Spaces: Public shared areas (e.g., "the_void", "dogs") \u2014 queries Memory_spaces_public filtered by space_ids
|
|
6064
|
+
- Groups: Private group collections \u2014 queries Memory_groups_{groupId} for each specified group
|
|
6065
|
+
- Neither specified: Searches all public memories across Memory_spaces_public
|
|
6066
|
+
|
|
6067
|
+
Results from multiple sources are merged and deduplicated by composite ID, sorted by relevance.
|
|
4858
6068
|
|
|
4859
6069
|
\u26A0\uFE0F **CRITICAL - CONTENT TYPE FILTERING**: Do NOT add content_type filter unless the user explicitly requests filtering by type.
|
|
4860
6070
|
- \u2705 CORRECT: User says "search The Void for hiking" \u2192 { spaces: ["the_void"], query: "hiking" }
|
|
@@ -4867,7 +6077,7 @@ Let the search algorithm find ALL relevant memories regardless of type unless ex
|
|
|
4867
6077
|
properties: {
|
|
4868
6078
|
query: {
|
|
4869
6079
|
type: "string",
|
|
4870
|
-
description: "Search query
|
|
6080
|
+
description: "Search query"
|
|
4871
6081
|
},
|
|
4872
6082
|
spaces: {
|
|
4873
6083
|
type: "array",
|
|
@@ -4875,9 +6085,20 @@ Let the search algorithm find ALL relevant memories regardless of type unless ex
|
|
|
4875
6085
|
type: "string",
|
|
4876
6086
|
enum: SUPPORTED_SPACES
|
|
4877
6087
|
},
|
|
4878
|
-
description: 'Spaces to search (e.g., ["the_void", "dogs"]).
|
|
4879
|
-
minItems: 1
|
|
4880
|
-
|
|
6088
|
+
description: 'Spaces to search (e.g., ["the_void", "dogs"]). Omit to search all public spaces.',
|
|
6089
|
+
minItems: 1
|
|
6090
|
+
},
|
|
6091
|
+
groups: {
|
|
6092
|
+
type: "array",
|
|
6093
|
+
items: { type: "string" },
|
|
6094
|
+
description: 'Group IDs to search (e.g., ["group-123"]). Searches Memory_groups_{groupId} for each.',
|
|
6095
|
+
minItems: 1
|
|
6096
|
+
},
|
|
6097
|
+
search_type: {
|
|
6098
|
+
type: "string",
|
|
6099
|
+
enum: ["hybrid", "bm25", "semantic"],
|
|
6100
|
+
description: 'Search algorithm: "hybrid" (default), "bm25" (keyword only), or "semantic" (vector only)',
|
|
6101
|
+
default: "hybrid"
|
|
4881
6102
|
},
|
|
4882
6103
|
content_type: {
|
|
4883
6104
|
type: "string",
|
|
@@ -4908,6 +6129,12 @@ Let the search algorithm find ALL relevant memories regardless of type unless ex
|
|
|
4908
6129
|
type: "string",
|
|
4909
6130
|
description: "Filter memories created before this date (ISO 8601)"
|
|
4910
6131
|
},
|
|
6132
|
+
moderation_filter: {
|
|
6133
|
+
type: "string",
|
|
6134
|
+
enum: ["approved", "pending", "rejected", "removed", "all"],
|
|
6135
|
+
description: 'Filter by moderation status. Default: "approved" (only shows approved/unmoderated). Non-approved filters require moderator permissions.',
|
|
6136
|
+
default: "approved"
|
|
6137
|
+
},
|
|
4911
6138
|
include_comments: {
|
|
4912
6139
|
type: "boolean",
|
|
4913
6140
|
description: "Include comments in search results (default: false)",
|
|
@@ -4924,10 +6151,73 @@ Let the search algorithm find ALL relevant memories regardless of type unless ex
|
|
|
4924
6151
|
description: "Offset for pagination"
|
|
4925
6152
|
}
|
|
4926
6153
|
},
|
|
4927
|
-
required: ["query"
|
|
6154
|
+
required: ["query"]
|
|
6155
|
+
}
|
|
6156
|
+
};
|
|
6157
|
+
function buildModerationFilter(collection, moderationFilter = "approved") {
|
|
6158
|
+
if (moderationFilter === "all") {
|
|
6159
|
+
return null;
|
|
6160
|
+
}
|
|
6161
|
+
if (moderationFilter === "approved") {
|
|
6162
|
+
return Filters4.or(
|
|
6163
|
+
collection.filter.byProperty("moderation_status").equal("approved"),
|
|
6164
|
+
collection.filter.byProperty("moderation_status").isNull(true)
|
|
6165
|
+
);
|
|
6166
|
+
}
|
|
6167
|
+
return collection.filter.byProperty("moderation_status").equal(moderationFilter);
|
|
6168
|
+
}
|
|
6169
|
+
function buildBaseFilters(collection, args) {
|
|
6170
|
+
const filterList = [];
|
|
6171
|
+
filterList.push(collection.filter.byProperty("deleted_at").isNull(true));
|
|
6172
|
+
filterList.push(collection.filter.byProperty("doc_type").equal("memory"));
|
|
6173
|
+
const moderationFilter = buildModerationFilter(collection, args.moderation_filter);
|
|
6174
|
+
if (moderationFilter) {
|
|
6175
|
+
filterList.push(moderationFilter);
|
|
6176
|
+
}
|
|
6177
|
+
if (args.content_type) {
|
|
6178
|
+
filterList.push(collection.filter.byProperty("content_type").equal(args.content_type));
|
|
6179
|
+
}
|
|
6180
|
+
if (!args.include_comments && !args.content_type) {
|
|
6181
|
+
filterList.push(collection.filter.byProperty("content_type").notEqual("comment"));
|
|
6182
|
+
}
|
|
6183
|
+
if (!args.content_type) {
|
|
6184
|
+
filterList.push(collection.filter.byProperty("content_type").notEqual("ghost"));
|
|
6185
|
+
}
|
|
6186
|
+
if (args.tags && args.tags.length > 0) {
|
|
6187
|
+
args.tags.forEach((tag) => {
|
|
6188
|
+
filterList.push(collection.filter.byProperty("tags").containsAny([tag]));
|
|
6189
|
+
});
|
|
6190
|
+
}
|
|
6191
|
+
if (args.min_weight !== void 0) {
|
|
6192
|
+
filterList.push(collection.filter.byProperty("weight").greaterOrEqual(args.min_weight));
|
|
6193
|
+
}
|
|
6194
|
+
if (args.max_weight !== void 0) {
|
|
6195
|
+
filterList.push(collection.filter.byProperty("weight").lessOrEqual(args.max_weight));
|
|
6196
|
+
}
|
|
6197
|
+
if (args.date_from) {
|
|
6198
|
+
filterList.push(collection.filter.byProperty("created_at").greaterOrEqual(new Date(args.date_from)));
|
|
6199
|
+
}
|
|
6200
|
+
if (args.date_to) {
|
|
6201
|
+
filterList.push(collection.filter.byProperty("created_at").lessOrEqual(new Date(args.date_to)));
|
|
4928
6202
|
}
|
|
4929
|
-
|
|
4930
|
-
|
|
6203
|
+
return filterList;
|
|
6204
|
+
}
|
|
6205
|
+
async function executeSearch(collection, query, searchType, whereFilter, limit) {
|
|
6206
|
+
const opts = {
|
|
6207
|
+
limit,
|
|
6208
|
+
...whereFilter && { where: whereFilter }
|
|
6209
|
+
};
|
|
6210
|
+
switch (searchType) {
|
|
6211
|
+
case "bm25":
|
|
6212
|
+
return (await collection.query.bm25(query, opts)).objects;
|
|
6213
|
+
case "semantic":
|
|
6214
|
+
return (await collection.query.nearText([query], opts)).objects;
|
|
6215
|
+
case "hybrid":
|
|
6216
|
+
default:
|
|
6217
|
+
return (await collection.query.hybrid(query, opts)).objects;
|
|
6218
|
+
}
|
|
6219
|
+
}
|
|
6220
|
+
async function handleSearchSpace(args, userId, authContext) {
|
|
4931
6221
|
const debug = createDebugLogger({
|
|
4932
6222
|
tool: "remember_search_space",
|
|
4933
6223
|
userId,
|
|
@@ -4936,96 +6226,167 @@ async function handleSearchSpace(args, userId) {
|
|
|
4936
6226
|
try {
|
|
4937
6227
|
debug.info("Tool invoked");
|
|
4938
6228
|
debug.trace("Arguments", { args });
|
|
4939
|
-
|
|
4940
|
-
const
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
message: "Must specify at least one space to search"
|
|
4963
|
-
},
|
|
4964
|
-
null,
|
|
4965
|
-
2
|
|
4966
|
-
);
|
|
6229
|
+
const spaces = args.spaces || [];
|
|
6230
|
+
const groups = args.groups || [];
|
|
6231
|
+
const searchType = args.search_type || "hybrid";
|
|
6232
|
+
const limit = args.limit || 10;
|
|
6233
|
+
const offset = args.offset || 0;
|
|
6234
|
+
if (spaces.length > 0) {
|
|
6235
|
+
const invalidSpaces = spaces.filter((s) => !isValidSpaceId(s));
|
|
6236
|
+
if (invalidSpaces.length > 0) {
|
|
6237
|
+
return JSON.stringify(
|
|
6238
|
+
{
|
|
6239
|
+
success: false,
|
|
6240
|
+
error: "Invalid space IDs",
|
|
6241
|
+
message: `Invalid spaces: ${invalidSpaces.join(", ")}. Supported spaces: ${SUPPORTED_SPACES.join(", ")}`,
|
|
6242
|
+
context: {
|
|
6243
|
+
invalid_spaces: invalidSpaces,
|
|
6244
|
+
provided_spaces: spaces,
|
|
6245
|
+
supported_spaces: SUPPORTED_SPACES
|
|
6246
|
+
}
|
|
6247
|
+
},
|
|
6248
|
+
null,
|
|
6249
|
+
2
|
|
6250
|
+
);
|
|
6251
|
+
}
|
|
4967
6252
|
}
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
6253
|
+
if (groups.length > 0) {
|
|
6254
|
+
const invalidGroups = groups.filter((g) => !g || g.includes(".") || g.trim() === "");
|
|
6255
|
+
if (invalidGroups.length > 0) {
|
|
6256
|
+
return JSON.stringify(
|
|
6257
|
+
{
|
|
6258
|
+
success: false,
|
|
6259
|
+
error: "Invalid group IDs",
|
|
6260
|
+
message: "Group IDs cannot be empty or contain dots",
|
|
6261
|
+
context: { invalid_groups: invalidGroups }
|
|
6262
|
+
},
|
|
6263
|
+
null,
|
|
6264
|
+
2
|
|
6265
|
+
);
|
|
6266
|
+
}
|
|
4975
6267
|
}
|
|
4976
|
-
|
|
4977
|
-
|
|
6268
|
+
const moderationFilter = args.moderation_filter || "approved";
|
|
6269
|
+
if (moderationFilter !== "approved") {
|
|
6270
|
+
for (const groupId of groups) {
|
|
6271
|
+
if (!canModerate(authContext, groupId)) {
|
|
6272
|
+
return JSON.stringify(
|
|
6273
|
+
{
|
|
6274
|
+
success: false,
|
|
6275
|
+
error: "Permission denied",
|
|
6276
|
+
message: `Moderator access required to view ${moderationFilter} memories in group ${groupId}`
|
|
6277
|
+
},
|
|
6278
|
+
null,
|
|
6279
|
+
2
|
|
6280
|
+
);
|
|
6281
|
+
}
|
|
6282
|
+
}
|
|
6283
|
+
if ((spaces.length > 0 || groups.length === 0) && !canModerateAny(authContext)) {
|
|
6284
|
+
return JSON.stringify(
|
|
6285
|
+
{
|
|
6286
|
+
success: false,
|
|
6287
|
+
error: "Permission denied",
|
|
6288
|
+
message: `Moderator access required to view ${moderationFilter} memories in spaces`
|
|
6289
|
+
},
|
|
6290
|
+
null,
|
|
6291
|
+
2
|
|
6292
|
+
);
|
|
6293
|
+
}
|
|
4978
6294
|
}
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
6295
|
+
const weaviateClient = getWeaviateClient();
|
|
6296
|
+
const fetchLimit = (limit + offset) * Math.max(1, groups.length + (spaces.length > 0 || groups.length === 0 ? 1 : 0));
|
|
6297
|
+
const allObjects = [];
|
|
6298
|
+
logger.info("Starting space/group search", {
|
|
6299
|
+
tool: "remember_search_space",
|
|
6300
|
+
userId,
|
|
6301
|
+
spaces,
|
|
6302
|
+
groups,
|
|
6303
|
+
searchType,
|
|
6304
|
+
query: args.query
|
|
6305
|
+
});
|
|
6306
|
+
if (spaces.length > 0 || groups.length === 0) {
|
|
6307
|
+
const spacesCollectionName = getCollectionName("SPACES" /* SPACES */);
|
|
6308
|
+
const spacesCollection = weaviateClient.collections.get(spacesCollectionName);
|
|
6309
|
+
const filterList = buildBaseFilters(spacesCollection, args);
|
|
6310
|
+
if (spaces.length > 0) {
|
|
6311
|
+
filterList.push(spacesCollection.filter.byProperty("space_ids").containsAny(spaces));
|
|
6312
|
+
}
|
|
6313
|
+
const whereFilter = filterList.length > 0 ? Filters4.and(...filterList) : void 0;
|
|
6314
|
+
debug.debug("Searching Memory_spaces_public", {
|
|
6315
|
+
filterCount: filterList.length,
|
|
6316
|
+
spaces,
|
|
6317
|
+
allPublic: spaces.length === 0,
|
|
6318
|
+
searchType
|
|
6319
|
+
});
|
|
6320
|
+
const spaceObjects = await debug.time("Space collection search", async () => {
|
|
6321
|
+
return await executeSearch(spacesCollection, args.query, searchType, whereFilter, fetchLimit);
|
|
6322
|
+
});
|
|
6323
|
+
allObjects.push(...spaceObjects);
|
|
6324
|
+
logger.info("Space collection search complete", {
|
|
6325
|
+
tool: "remember_search_space",
|
|
6326
|
+
collectionName: spacesCollectionName,
|
|
6327
|
+
resultCount: spaceObjects.length
|
|
4982
6328
|
});
|
|
4983
6329
|
}
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
});
|
|
5003
|
-
const searchResults = await debug.time("Hybrid search query", async () => {
|
|
5004
|
-
return await publicCollection.query.hybrid(args.query, {
|
|
5005
|
-
limit: args.limit || 10,
|
|
5006
|
-
offset: args.offset || 0,
|
|
5007
|
-
...whereFilter && { where: whereFilter }
|
|
6330
|
+
for (const groupId of groups) {
|
|
6331
|
+
const groupCollectionName = getCollectionName("GROUPS" /* GROUPS */, groupId);
|
|
6332
|
+
const exists = await weaviateClient.collections.exists(groupCollectionName);
|
|
6333
|
+
if (!exists) {
|
|
6334
|
+
debug.warn("Group collection not found, skipping", { groupId, groupCollectionName });
|
|
6335
|
+
continue;
|
|
6336
|
+
}
|
|
6337
|
+
const groupCollection = weaviateClient.collections.get(groupCollectionName);
|
|
6338
|
+
const filterList = buildBaseFilters(groupCollection, args);
|
|
6339
|
+
const whereFilter = filterList.length > 0 ? Filters4.and(...filterList) : void 0;
|
|
6340
|
+
debug.debug("Searching group collection", {
|
|
6341
|
+
groupId,
|
|
6342
|
+
groupCollectionName,
|
|
6343
|
+
filterCount: filterList.length,
|
|
6344
|
+
searchType
|
|
6345
|
+
});
|
|
6346
|
+
const groupObjects = await debug.time(`Group collection search: ${groupId}`, async () => {
|
|
6347
|
+
return await executeSearch(groupCollection, args.query, searchType, whereFilter, fetchLimit);
|
|
5008
6348
|
});
|
|
6349
|
+
allObjects.push(...groupObjects);
|
|
6350
|
+
logger.info("Group collection search complete", {
|
|
6351
|
+
tool: "remember_search_space",
|
|
6352
|
+
groupId,
|
|
6353
|
+
collectionName: groupCollectionName,
|
|
6354
|
+
resultCount: groupObjects.length
|
|
6355
|
+
});
|
|
6356
|
+
}
|
|
6357
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6358
|
+
const deduplicated = allObjects.filter((obj) => {
|
|
6359
|
+
if (seen.has(obj.uuid))
|
|
6360
|
+
return false;
|
|
6361
|
+
seen.add(obj.uuid);
|
|
6362
|
+
return true;
|
|
5009
6363
|
});
|
|
5010
|
-
|
|
5011
|
-
|
|
6364
|
+
deduplicated.sort((a, b) => {
|
|
6365
|
+
const scoreA = a.metadata?.score ?? 0;
|
|
6366
|
+
const scoreB = b.metadata?.score ?? 0;
|
|
6367
|
+
return scoreB - scoreA;
|
|
5012
6368
|
});
|
|
5013
|
-
const
|
|
6369
|
+
const paginated = deduplicated.slice(offset, offset + limit);
|
|
6370
|
+
const memories = paginated.map((obj) => ({
|
|
5014
6371
|
id: obj.uuid,
|
|
5015
6372
|
...obj.properties,
|
|
5016
6373
|
_score: obj.metadata?.score
|
|
5017
6374
|
}));
|
|
6375
|
+
const isAllPublic = spaces.length === 0 && groups.length === 0;
|
|
5018
6376
|
const result = {
|
|
5019
|
-
spaces_searched:
|
|
6377
|
+
spaces_searched: isAllPublic ? "all_public" : spaces,
|
|
6378
|
+
groups_searched: groups,
|
|
5020
6379
|
query: args.query,
|
|
6380
|
+
search_type: searchType,
|
|
5021
6381
|
memories,
|
|
5022
6382
|
total: memories.length,
|
|
5023
|
-
offset
|
|
5024
|
-
limit
|
|
6383
|
+
offset,
|
|
6384
|
+
limit
|
|
5025
6385
|
};
|
|
5026
6386
|
debug.info("Tool completed successfully", {
|
|
5027
6387
|
resultCount: memories.length,
|
|
5028
|
-
spaces
|
|
6388
|
+
spaces,
|
|
6389
|
+
groups
|
|
5029
6390
|
});
|
|
5030
6391
|
return JSON.stringify(result, null, 2);
|
|
5031
6392
|
} catch (error) {
|
|
@@ -5037,6 +6398,7 @@ async function handleSearchSpace(args, userId) {
|
|
|
5037
6398
|
toolName: "remember_search_space",
|
|
5038
6399
|
operation: "search spaces",
|
|
5039
6400
|
spaces: args.spaces,
|
|
6401
|
+
groups: args.groups,
|
|
5040
6402
|
query: args.query
|
|
5041
6403
|
});
|
|
5042
6404
|
}
|
|
@@ -5095,6 +6457,12 @@ Let the query algorithm find ALL relevant memories regardless of type unless exp
|
|
|
5095
6457
|
type: "string",
|
|
5096
6458
|
description: "Filter memories created before this date (ISO 8601)"
|
|
5097
6459
|
},
|
|
6460
|
+
moderation_filter: {
|
|
6461
|
+
type: "string",
|
|
6462
|
+
enum: ["approved", "pending", "rejected", "removed", "all"],
|
|
6463
|
+
description: 'Filter by moderation status. Default: "approved" (only shows approved/unmoderated). Non-approved filters require moderator permissions.',
|
|
6464
|
+
default: "approved"
|
|
6465
|
+
},
|
|
5098
6466
|
include_comments: {
|
|
5099
6467
|
type: "boolean",
|
|
5100
6468
|
description: "Include comments in query results (default: false)",
|
|
@@ -5115,7 +6483,7 @@ Let the query algorithm find ALL relevant memories regardless of type unless exp
|
|
|
5115
6483
|
required: ["question", "spaces"]
|
|
5116
6484
|
}
|
|
5117
6485
|
};
|
|
5118
|
-
async function handleQuerySpace(args, userId) {
|
|
6486
|
+
async function handleQuerySpace(args, userId, authContext) {
|
|
5119
6487
|
const debug = createDebugLogger({
|
|
5120
6488
|
tool: "remember_query_space",
|
|
5121
6489
|
userId,
|
|
@@ -5148,16 +6516,35 @@ async function handleQuerySpace(args, userId) {
|
|
|
5148
6516
|
2
|
|
5149
6517
|
);
|
|
5150
6518
|
}
|
|
6519
|
+
const moderationFilterValue = args.moderation_filter || "approved";
|
|
6520
|
+
if (moderationFilterValue !== "approved" && !canModerateAny(authContext)) {
|
|
6521
|
+
return JSON.stringify(
|
|
6522
|
+
{
|
|
6523
|
+
success: false,
|
|
6524
|
+
error: "Permission denied",
|
|
6525
|
+
message: `Moderator access required to view ${moderationFilterValue} memories in spaces`
|
|
6526
|
+
},
|
|
6527
|
+
null,
|
|
6528
|
+
2
|
|
6529
|
+
);
|
|
6530
|
+
}
|
|
5151
6531
|
const weaviateClient = getWeaviateClient();
|
|
5152
6532
|
const publicCollection = await ensurePublicCollection(weaviateClient);
|
|
5153
6533
|
const filterList = [];
|
|
5154
6534
|
filterList.push(publicCollection.filter.byProperty("spaces").containsAny(args.spaces));
|
|
5155
6535
|
filterList.push(publicCollection.filter.byProperty("doc_type").equal("memory"));
|
|
6536
|
+
const moderationFilter = buildModerationFilter(publicCollection, args.moderation_filter);
|
|
6537
|
+
if (moderationFilter) {
|
|
6538
|
+
filterList.push(moderationFilter);
|
|
6539
|
+
}
|
|
5156
6540
|
if (args.content_type) {
|
|
5157
|
-
filterList.push(publicCollection.filter.byProperty("
|
|
6541
|
+
filterList.push(publicCollection.filter.byProperty("content_type").equal(args.content_type));
|
|
5158
6542
|
}
|
|
5159
6543
|
if (!args.include_comments && !args.content_type) {
|
|
5160
|
-
filterList.push(publicCollection.filter.byProperty("
|
|
6544
|
+
filterList.push(publicCollection.filter.byProperty("content_type").notEqual("comment"));
|
|
6545
|
+
}
|
|
6546
|
+
if (!args.content_type) {
|
|
6547
|
+
filterList.push(publicCollection.filter.byProperty("content_type").notEqual("ghost"));
|
|
5161
6548
|
}
|
|
5162
6549
|
if (args.tags && args.tags.length > 0) {
|
|
5163
6550
|
args.tags.forEach((tag) => {
|
|
@@ -5236,6 +6623,353 @@ async function handleQuerySpace(args, userId) {
|
|
|
5236
6623
|
}
|
|
5237
6624
|
}
|
|
5238
6625
|
|
|
6626
|
+
// src/tools/moderate.ts
|
|
6627
|
+
init_logger();
|
|
6628
|
+
var ACTION_TO_STATUS = {
|
|
6629
|
+
approve: "approved",
|
|
6630
|
+
reject: "rejected",
|
|
6631
|
+
remove: "removed"
|
|
6632
|
+
};
|
|
6633
|
+
var moderateTool = {
|
|
6634
|
+
name: "remember_moderate",
|
|
6635
|
+
description: `Approve, reject, or remove a published memory. Requires moderator permissions (can_moderate).
|
|
6636
|
+
|
|
6637
|
+
Actions:
|
|
6638
|
+
- approve: Mark a pending memory as approved (visible in default searches)
|
|
6639
|
+
- reject: Reject a pending memory (hidden from default searches)
|
|
6640
|
+
- remove: Remove a previously approved memory (hidden from default searches)
|
|
6641
|
+
|
|
6642
|
+
Must specify either space_id or group_id to identify where the memory is published.`,
|
|
6643
|
+
inputSchema: {
|
|
6644
|
+
type: "object",
|
|
6645
|
+
properties: {
|
|
6646
|
+
memory_id: {
|
|
6647
|
+
type: "string",
|
|
6648
|
+
description: "UUID or composite ID of the published memory"
|
|
6649
|
+
},
|
|
6650
|
+
space_id: {
|
|
6651
|
+
type: "string",
|
|
6652
|
+
description: "Space containing the memory (searches Memory_spaces_public filtered by space_ids)"
|
|
6653
|
+
},
|
|
6654
|
+
group_id: {
|
|
6655
|
+
type: "string",
|
|
6656
|
+
description: "Group containing the memory (searches Memory_groups_{groupId})"
|
|
6657
|
+
},
|
|
6658
|
+
action: {
|
|
6659
|
+
type: "string",
|
|
6660
|
+
enum: ["approve", "reject", "remove"],
|
|
6661
|
+
description: "Moderation action to perform"
|
|
6662
|
+
},
|
|
6663
|
+
reason: {
|
|
6664
|
+
type: "string",
|
|
6665
|
+
description: "Optional reason for the moderation action"
|
|
6666
|
+
}
|
|
6667
|
+
},
|
|
6668
|
+
required: ["memory_id", "action"]
|
|
6669
|
+
}
|
|
6670
|
+
};
|
|
6671
|
+
async function handleModerate(args, userId, authContext) {
|
|
6672
|
+
const debug = createDebugLogger({
|
|
6673
|
+
tool: "remember_moderate",
|
|
6674
|
+
userId,
|
|
6675
|
+
operation: "moderate"
|
|
6676
|
+
});
|
|
6677
|
+
try {
|
|
6678
|
+
debug.info("Tool invoked");
|
|
6679
|
+
debug.trace("Arguments", { args });
|
|
6680
|
+
const { memory_id, space_id, group_id, action, reason } = args;
|
|
6681
|
+
if (!space_id && !group_id) {
|
|
6682
|
+
return JSON.stringify(
|
|
6683
|
+
{
|
|
6684
|
+
success: false,
|
|
6685
|
+
error: "Missing destination",
|
|
6686
|
+
message: "Must specify either space_id or group_id"
|
|
6687
|
+
},
|
|
6688
|
+
null,
|
|
6689
|
+
2
|
|
6690
|
+
);
|
|
6691
|
+
}
|
|
6692
|
+
if (!ACTION_TO_STATUS[action]) {
|
|
6693
|
+
return JSON.stringify(
|
|
6694
|
+
{
|
|
6695
|
+
success: false,
|
|
6696
|
+
error: "Invalid action",
|
|
6697
|
+
message: `Action must be one of: approve, reject, remove`
|
|
6698
|
+
},
|
|
6699
|
+
null,
|
|
6700
|
+
2
|
|
6701
|
+
);
|
|
6702
|
+
}
|
|
6703
|
+
if (group_id) {
|
|
6704
|
+
if (!canModerate(authContext, group_id)) {
|
|
6705
|
+
return JSON.stringify(
|
|
6706
|
+
{
|
|
6707
|
+
success: false,
|
|
6708
|
+
error: "Permission denied",
|
|
6709
|
+
message: `Moderator access required for group ${group_id}`
|
|
6710
|
+
},
|
|
6711
|
+
null,
|
|
6712
|
+
2
|
|
6713
|
+
);
|
|
6714
|
+
}
|
|
6715
|
+
} else if (space_id) {
|
|
6716
|
+
if (!canModerateAny(authContext)) {
|
|
6717
|
+
return JSON.stringify(
|
|
6718
|
+
{
|
|
6719
|
+
success: false,
|
|
6720
|
+
error: "Permission denied",
|
|
6721
|
+
message: `Moderator access required to moderate memories in spaces`
|
|
6722
|
+
},
|
|
6723
|
+
null,
|
|
6724
|
+
2
|
|
6725
|
+
);
|
|
6726
|
+
}
|
|
6727
|
+
}
|
|
6728
|
+
const weaviateClient = getWeaviateClient();
|
|
6729
|
+
let collection;
|
|
6730
|
+
if (group_id) {
|
|
6731
|
+
const collectionName = getCollectionName("GROUPS" /* GROUPS */, group_id);
|
|
6732
|
+
collection = weaviateClient.collections.get(collectionName);
|
|
6733
|
+
} else {
|
|
6734
|
+
collection = await ensurePublicCollection(weaviateClient);
|
|
6735
|
+
}
|
|
6736
|
+
const memory = await fetchMemoryWithAllProperties(collection, memory_id);
|
|
6737
|
+
if (!memory) {
|
|
6738
|
+
return JSON.stringify(
|
|
6739
|
+
{
|
|
6740
|
+
success: false,
|
|
6741
|
+
error: "Memory not found",
|
|
6742
|
+
message: `Published memory ${memory_id} not found in ${group_id ? `group ${group_id}` : `space ${space_id}`}`
|
|
6743
|
+
},
|
|
6744
|
+
null,
|
|
6745
|
+
2
|
|
6746
|
+
);
|
|
6747
|
+
}
|
|
6748
|
+
const newStatus = ACTION_TO_STATUS[action];
|
|
6749
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6750
|
+
await collection.data.update({
|
|
6751
|
+
id: memory_id,
|
|
6752
|
+
properties: {
|
|
6753
|
+
moderation_status: newStatus,
|
|
6754
|
+
moderated_by: userId,
|
|
6755
|
+
moderated_at: now
|
|
6756
|
+
}
|
|
6757
|
+
});
|
|
6758
|
+
logger.info("Memory moderated", {
|
|
6759
|
+
tool: "remember_moderate",
|
|
6760
|
+
userId,
|
|
6761
|
+
memoryId: memory_id,
|
|
6762
|
+
action,
|
|
6763
|
+
newStatus,
|
|
6764
|
+
spaceId: space_id,
|
|
6765
|
+
groupId: group_id,
|
|
6766
|
+
reason
|
|
6767
|
+
});
|
|
6768
|
+
return JSON.stringify(
|
|
6769
|
+
{
|
|
6770
|
+
success: true,
|
|
6771
|
+
memory_id,
|
|
6772
|
+
action,
|
|
6773
|
+
moderation_status: newStatus,
|
|
6774
|
+
moderated_by: userId,
|
|
6775
|
+
moderated_at: now,
|
|
6776
|
+
reason: reason || void 0,
|
|
6777
|
+
location: group_id ? `group:${group_id}` : `space:${space_id}`
|
|
6778
|
+
},
|
|
6779
|
+
null,
|
|
6780
|
+
2
|
|
6781
|
+
);
|
|
6782
|
+
} catch (error) {
|
|
6783
|
+
debug.error("Tool failed", {
|
|
6784
|
+
error: error instanceof Error ? error.message : String(error),
|
|
6785
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
6786
|
+
});
|
|
6787
|
+
return handleToolError(error, {
|
|
6788
|
+
toolName: "remember_moderate",
|
|
6789
|
+
operation: "moderate memory",
|
|
6790
|
+
memoryId: args.memory_id,
|
|
6791
|
+
action: args.action
|
|
6792
|
+
});
|
|
6793
|
+
}
|
|
6794
|
+
}
|
|
6795
|
+
|
|
6796
|
+
// src/tools/ghost-config.ts
|
|
6797
|
+
init_ghost_config_service();
|
|
6798
|
+
var ghostConfigTool = {
|
|
6799
|
+
name: "remember_ghost_config",
|
|
6800
|
+
description: `Manage ghost/persona configuration. Controls who can interact with your ghost and at what trust level.
|
|
6801
|
+
|
|
6802
|
+
Actions:
|
|
6803
|
+
- get: View current ghost configuration
|
|
6804
|
+
- set: Update ghost settings (enabled, trust defaults, enforcement mode)
|
|
6805
|
+
- set_trust: Set a per-user trust level override (0-1)
|
|
6806
|
+
- remove_trust: Remove a per-user trust override (revert to default)
|
|
6807
|
+
- block: Block a user from ghost access entirely
|
|
6808
|
+
- unblock: Unblock a previously blocked user
|
|
6809
|
+
|
|
6810
|
+
Trust levels control what information your ghost can share:
|
|
6811
|
+
- 0.0: Existence only ("A memory exists about this")
|
|
6812
|
+
- 0.25: Metadata only (tags, type, dates \u2014 no content)
|
|
6813
|
+
- 0.5: Summary only (AI-generated summary, no raw content)
|
|
6814
|
+
- 0.75: Partial access (content with sensitive fields redacted)
|
|
6815
|
+
- 1.0: Full access (all content revealed)
|
|
6816
|
+
|
|
6817
|
+
Ghost is disabled by default. Enable it to allow others to chat with your AI representation.`,
|
|
6818
|
+
inputSchema: {
|
|
6819
|
+
type: "object",
|
|
6820
|
+
properties: {
|
|
6821
|
+
action: {
|
|
6822
|
+
type: "string",
|
|
6823
|
+
enum: ["get", "set", "set_trust", "remove_trust", "block", "unblock"],
|
|
6824
|
+
description: "Action to perform"
|
|
6825
|
+
},
|
|
6826
|
+
// For 'set' action
|
|
6827
|
+
enabled: {
|
|
6828
|
+
type: "boolean",
|
|
6829
|
+
description: 'Enable/disable ghost conversations (for "set" action)'
|
|
6830
|
+
},
|
|
6831
|
+
public_ghost_enabled: {
|
|
6832
|
+
type: "boolean",
|
|
6833
|
+
description: 'Allow non-friends to chat with ghost (for "set" action)'
|
|
6834
|
+
},
|
|
6835
|
+
default_friend_trust: {
|
|
6836
|
+
type: "number",
|
|
6837
|
+
description: 'Default trust level for friends (0-1, for "set" action)',
|
|
6838
|
+
minimum: 0,
|
|
6839
|
+
maximum: 1
|
|
6840
|
+
},
|
|
6841
|
+
default_public_trust: {
|
|
6842
|
+
type: "number",
|
|
6843
|
+
description: 'Default trust level for strangers (0-1, for "set" action)',
|
|
6844
|
+
minimum: 0,
|
|
6845
|
+
maximum: 1
|
|
6846
|
+
},
|
|
6847
|
+
enforcement_mode: {
|
|
6848
|
+
type: "string",
|
|
6849
|
+
enum: ["query", "prompt", "hybrid"],
|
|
6850
|
+
description: 'Trust enforcement mode (for "set" action). "query" (default) is most secure.'
|
|
6851
|
+
},
|
|
6852
|
+
// For 'set_trust' / 'remove_trust' / 'block' / 'unblock' actions
|
|
6853
|
+
target_user_id: {
|
|
6854
|
+
type: "string",
|
|
6855
|
+
description: "Target user ID (for set_trust, remove_trust, block, unblock)"
|
|
6856
|
+
},
|
|
6857
|
+
trust_level: {
|
|
6858
|
+
type: "number",
|
|
6859
|
+
description: 'Trust level to assign (0-1, for "set_trust" action)',
|
|
6860
|
+
minimum: 0,
|
|
6861
|
+
maximum: 1
|
|
6862
|
+
}
|
|
6863
|
+
},
|
|
6864
|
+
required: ["action"]
|
|
6865
|
+
}
|
|
6866
|
+
};
|
|
6867
|
+
async function handleGhostConfig(args, userId, authContext) {
|
|
6868
|
+
const debug = createDebugLogger({ tool: "remember_ghost_config", userId, operation: args.action });
|
|
6869
|
+
try {
|
|
6870
|
+
debug.info("Tool invoked");
|
|
6871
|
+
debug.trace("Arguments", { args });
|
|
6872
|
+
switch (args.action) {
|
|
6873
|
+
case "get": {
|
|
6874
|
+
const config2 = await getGhostConfig(userId);
|
|
6875
|
+
return JSON.stringify({
|
|
6876
|
+
success: true,
|
|
6877
|
+
config: config2,
|
|
6878
|
+
trust_tier_guide: {
|
|
6879
|
+
"0.0": "Existence only",
|
|
6880
|
+
"0.25": "Metadata only (default friend trust)",
|
|
6881
|
+
"0.5": "Summary only",
|
|
6882
|
+
"0.75": "Partial access",
|
|
6883
|
+
"1.0": "Full access"
|
|
6884
|
+
}
|
|
6885
|
+
}, null, 2);
|
|
6886
|
+
}
|
|
6887
|
+
case "set": {
|
|
6888
|
+
const updates = {};
|
|
6889
|
+
if (args.enabled !== void 0)
|
|
6890
|
+
updates.enabled = args.enabled;
|
|
6891
|
+
if (args.public_ghost_enabled !== void 0)
|
|
6892
|
+
updates.public_ghost_enabled = args.public_ghost_enabled;
|
|
6893
|
+
if (args.default_friend_trust !== void 0)
|
|
6894
|
+
updates.default_friend_trust = args.default_friend_trust;
|
|
6895
|
+
if (args.default_public_trust !== void 0)
|
|
6896
|
+
updates.default_public_trust = args.default_public_trust;
|
|
6897
|
+
if (args.enforcement_mode !== void 0)
|
|
6898
|
+
updates.enforcement_mode = args.enforcement_mode;
|
|
6899
|
+
if (Object.keys(updates).length === 0) {
|
|
6900
|
+
throw new Error("No fields to update. Provide at least one of: enabled, public_ghost_enabled, default_friend_trust, default_public_trust, enforcement_mode");
|
|
6901
|
+
}
|
|
6902
|
+
validateGhostConfigUpdate(updates);
|
|
6903
|
+
const config2 = await setGhostConfigFields(userId, updates);
|
|
6904
|
+
return JSON.stringify({
|
|
6905
|
+
success: true,
|
|
6906
|
+
message: "Ghost configuration updated",
|
|
6907
|
+
updated_fields: Object.keys(updates),
|
|
6908
|
+
config: config2
|
|
6909
|
+
}, null, 2);
|
|
6910
|
+
}
|
|
6911
|
+
case "set_trust": {
|
|
6912
|
+
if (!args.target_user_id) {
|
|
6913
|
+
throw new Error("target_user_id is required for set_trust action");
|
|
6914
|
+
}
|
|
6915
|
+
if (args.trust_level === void 0) {
|
|
6916
|
+
throw new Error("trust_level is required for set_trust action");
|
|
6917
|
+
}
|
|
6918
|
+
await setUserTrust(userId, args.target_user_id, args.trust_level);
|
|
6919
|
+
return JSON.stringify({
|
|
6920
|
+
success: true,
|
|
6921
|
+
message: `Trust level for ${args.target_user_id} set to ${args.trust_level}`,
|
|
6922
|
+
target_user_id: args.target_user_id,
|
|
6923
|
+
trust_level: args.trust_level
|
|
6924
|
+
}, null, 2);
|
|
6925
|
+
}
|
|
6926
|
+
case "remove_trust": {
|
|
6927
|
+
if (!args.target_user_id) {
|
|
6928
|
+
throw new Error("target_user_id is required for remove_trust action");
|
|
6929
|
+
}
|
|
6930
|
+
await removeUserTrust(userId, args.target_user_id);
|
|
6931
|
+
return JSON.stringify({
|
|
6932
|
+
success: true,
|
|
6933
|
+
message: `Trust override for ${args.target_user_id} removed (reverted to default)`,
|
|
6934
|
+
target_user_id: args.target_user_id
|
|
6935
|
+
}, null, 2);
|
|
6936
|
+
}
|
|
6937
|
+
case "block": {
|
|
6938
|
+
if (!args.target_user_id) {
|
|
6939
|
+
throw new Error("target_user_id is required for block action");
|
|
6940
|
+
}
|
|
6941
|
+
await blockUser(userId, args.target_user_id);
|
|
6942
|
+
return JSON.stringify({
|
|
6943
|
+
success: true,
|
|
6944
|
+
message: `${args.target_user_id} blocked from ghost access`,
|
|
6945
|
+
target_user_id: args.target_user_id
|
|
6946
|
+
}, null, 2);
|
|
6947
|
+
}
|
|
6948
|
+
case "unblock": {
|
|
6949
|
+
if (!args.target_user_id) {
|
|
6950
|
+
throw new Error("target_user_id is required for unblock action");
|
|
6951
|
+
}
|
|
6952
|
+
await unblockUser(userId, args.target_user_id);
|
|
6953
|
+
return JSON.stringify({
|
|
6954
|
+
success: true,
|
|
6955
|
+
message: `${args.target_user_id} unblocked from ghost access`,
|
|
6956
|
+
target_user_id: args.target_user_id
|
|
6957
|
+
}, null, 2);
|
|
6958
|
+
}
|
|
6959
|
+
default:
|
|
6960
|
+
throw new Error(`Unknown action: ${args.action}. Valid actions: get, set, set_trust, remove_trust, block, unblock`);
|
|
6961
|
+
}
|
|
6962
|
+
} catch (error) {
|
|
6963
|
+
debug.error("Tool failed", { error: error instanceof Error ? error.message : String(error) });
|
|
6964
|
+
handleToolError(error, {
|
|
6965
|
+
toolName: "remember_ghost_config",
|
|
6966
|
+
operation: args.action,
|
|
6967
|
+
userId
|
|
6968
|
+
});
|
|
6969
|
+
throw error;
|
|
6970
|
+
}
|
|
6971
|
+
}
|
|
6972
|
+
|
|
5239
6973
|
// src/server-factory.ts
|
|
5240
6974
|
var databasesInitialized = false;
|
|
5241
6975
|
var initializationPromise = null;
|
|
@@ -5285,10 +7019,27 @@ async function createServer(accessToken, userId, options = {}) {
|
|
|
5285
7019
|
}
|
|
5286
7020
|
}
|
|
5287
7021
|
);
|
|
5288
|
-
|
|
7022
|
+
let resolvedGhostMode;
|
|
7023
|
+
if (options.ghostMode) {
|
|
7024
|
+
const { getGhostConfig: getGhostConfig2 } = await Promise.resolve().then(() => (init_ghost_config_service(), ghost_config_service_exports));
|
|
7025
|
+
const { resolveAccessorTrustLevel: resolveAccessorTrustLevel2 } = await Promise.resolve().then(() => (init_access_control(), access_control_exports));
|
|
7026
|
+
const ghostConfig = await getGhostConfig2(options.ghostMode.owner_user_id);
|
|
7027
|
+
const trustLevel = resolveAccessorTrustLevel2(ghostConfig, options.ghostMode.accessor_user_id);
|
|
7028
|
+
resolvedGhostMode = {
|
|
7029
|
+
owner_user_id: options.ghostMode.owner_user_id,
|
|
7030
|
+
accessor_user_id: options.ghostMode.accessor_user_id,
|
|
7031
|
+
accessor_trust_level: trustLevel
|
|
7032
|
+
};
|
|
7033
|
+
logger.info("Ghost mode resolved", {
|
|
7034
|
+
ownerUserId: resolvedGhostMode.owner_user_id,
|
|
7035
|
+
accessorUserId: resolvedGhostMode.accessor_user_id,
|
|
7036
|
+
trustLevel: resolvedGhostMode.accessor_trust_level
|
|
7037
|
+
});
|
|
7038
|
+
}
|
|
7039
|
+
registerHandlers(server, userId, accessToken, resolvedGhostMode);
|
|
5289
7040
|
return server;
|
|
5290
7041
|
}
|
|
5291
|
-
function registerHandlers(server, userId, accessToken) {
|
|
7042
|
+
function registerHandlers(server, userId, accessToken, ghostMode) {
|
|
5292
7043
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
5293
7044
|
return {
|
|
5294
7045
|
tools: [
|
|
@@ -5309,68 +7060,86 @@ function registerHandlers(server, userId, accessToken) {
|
|
|
5309
7060
|
getPreferencesTool,
|
|
5310
7061
|
// Space tools
|
|
5311
7062
|
publishTool,
|
|
7063
|
+
retractTool,
|
|
7064
|
+
reviseTool,
|
|
5312
7065
|
confirmTool,
|
|
5313
7066
|
denyTool,
|
|
5314
7067
|
searchSpaceTool,
|
|
5315
|
-
querySpaceTool
|
|
7068
|
+
querySpaceTool,
|
|
7069
|
+
moderateTool,
|
|
7070
|
+
ghostConfigTool
|
|
5316
7071
|
]
|
|
5317
7072
|
};
|
|
5318
7073
|
});
|
|
5319
7074
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
5320
7075
|
const { name, arguments: args } = request.params;
|
|
5321
7076
|
try {
|
|
7077
|
+
const credentials = await credentialsProvider.getCredentials(accessToken, userId);
|
|
7078
|
+
const authContext = { accessToken, credentials, ghostMode };
|
|
5322
7079
|
let result;
|
|
5323
7080
|
switch (name) {
|
|
5324
7081
|
case "remember_create_memory":
|
|
5325
|
-
result = await handleCreateMemory(args, userId);
|
|
7082
|
+
result = await handleCreateMemory(args, userId, authContext);
|
|
5326
7083
|
break;
|
|
5327
7084
|
case "remember_search_memory":
|
|
5328
|
-
result = await handleSearchMemory(args, userId);
|
|
7085
|
+
result = await handleSearchMemory(args, userId, authContext);
|
|
5329
7086
|
break;
|
|
5330
7087
|
case "remember_delete_memory":
|
|
5331
|
-
result = await handleDeleteMemory(args, userId);
|
|
7088
|
+
result = await handleDeleteMemory(args, userId, authContext);
|
|
5332
7089
|
break;
|
|
5333
7090
|
case "remember_update_memory":
|
|
5334
|
-
result = await handleUpdateMemory(args, userId);
|
|
7091
|
+
result = await handleUpdateMemory(args, userId, authContext);
|
|
5335
7092
|
break;
|
|
5336
7093
|
case "remember_find_similar":
|
|
5337
|
-
result = await handleFindSimilar(args, userId);
|
|
7094
|
+
result = await handleFindSimilar(args, userId, authContext);
|
|
5338
7095
|
break;
|
|
5339
7096
|
case "remember_query_memory":
|
|
5340
|
-
result = await handleQueryMemory(args, userId);
|
|
7097
|
+
result = await handleQueryMemory(args, userId, authContext);
|
|
5341
7098
|
break;
|
|
5342
7099
|
case "remember_create_relationship":
|
|
5343
|
-
result = await handleCreateRelationship(args, userId);
|
|
7100
|
+
result = await handleCreateRelationship(args, userId, authContext);
|
|
5344
7101
|
break;
|
|
5345
7102
|
case "remember_update_relationship":
|
|
5346
|
-
result = await handleUpdateRelationship(args, userId);
|
|
7103
|
+
result = await handleUpdateRelationship(args, userId, authContext);
|
|
5347
7104
|
break;
|
|
5348
7105
|
case "remember_search_relationship":
|
|
5349
|
-
result = await handleSearchRelationship(args, userId);
|
|
7106
|
+
result = await handleSearchRelationship(args, userId, authContext);
|
|
5350
7107
|
break;
|
|
5351
7108
|
case "remember_delete_relationship":
|
|
5352
|
-
result = await handleDeleteRelationship(args, userId);
|
|
7109
|
+
result = await handleDeleteRelationship(args, userId, authContext);
|
|
5353
7110
|
break;
|
|
5354
7111
|
case "remember_set_preference":
|
|
5355
|
-
result = await handleSetPreference(args, userId);
|
|
7112
|
+
result = await handleSetPreference(args, userId, authContext);
|
|
5356
7113
|
break;
|
|
5357
7114
|
case "remember_get_preferences":
|
|
5358
|
-
result = await handleGetPreferences(args, userId);
|
|
7115
|
+
result = await handleGetPreferences(args, userId, authContext);
|
|
5359
7116
|
break;
|
|
5360
7117
|
case "remember_publish":
|
|
5361
|
-
result = await handlePublish(args, userId);
|
|
7118
|
+
result = await handlePublish(args, userId, authContext);
|
|
7119
|
+
break;
|
|
7120
|
+
case "remember_retract":
|
|
7121
|
+
result = await handleRetract(args, userId, authContext);
|
|
7122
|
+
break;
|
|
7123
|
+
case "remember_revise":
|
|
7124
|
+
result = await handleRevise(args, userId, authContext);
|
|
5362
7125
|
break;
|
|
5363
7126
|
case "remember_confirm":
|
|
5364
|
-
result = await handleConfirm(args, userId);
|
|
7127
|
+
result = await handleConfirm(args, userId, authContext);
|
|
5365
7128
|
break;
|
|
5366
7129
|
case "remember_deny":
|
|
5367
|
-
result = await handleDeny(args, userId);
|
|
7130
|
+
result = await handleDeny(args, userId, authContext);
|
|
5368
7131
|
break;
|
|
5369
7132
|
case "remember_search_space":
|
|
5370
|
-
result = await handleSearchSpace(args, userId);
|
|
7133
|
+
result = await handleSearchSpace(args, userId, authContext);
|
|
5371
7134
|
break;
|
|
5372
7135
|
case "remember_query_space":
|
|
5373
|
-
result = await handleQuerySpace(args, userId);
|
|
7136
|
+
result = await handleQuerySpace(args, userId, authContext);
|
|
7137
|
+
break;
|
|
7138
|
+
case "remember_moderate":
|
|
7139
|
+
result = await handleModerate(args, userId, authContext);
|
|
7140
|
+
break;
|
|
7141
|
+
case "remember_ghost_config":
|
|
7142
|
+
result = await handleGhostConfig(args, userId, authContext);
|
|
5374
7143
|
break;
|
|
5375
7144
|
default:
|
|
5376
7145
|
throw new McpError(
|