@prmichaelsen/remember-mcp 2.7.11 → 3.0.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/.env.example +6 -0
- package/AGENT.md +224 -21
- package/CHANGELOG.md +155 -915
- package/README.md +130 -1
- package/agent/commands/acp.command-create.md +372 -0
- package/agent/commands/acp.design-create.md +224 -0
- package/agent/commands/acp.init.md +39 -5
- package/agent/commands/acp.package-create.md +894 -0
- package/agent/commands/acp.package-info.md +211 -0
- package/agent/commands/acp.package-install.md +206 -33
- package/agent/commands/acp.package-list.md +279 -0
- package/agent/commands/acp.package-publish.md +540 -0
- package/agent/commands/acp.package-remove.md +292 -0
- package/agent/commands/acp.package-search.md +306 -0
- package/agent/commands/acp.package-update.md +360 -0
- package/agent/commands/acp.package-validate.md +539 -0
- package/agent/commands/acp.pattern-create.md +326 -0
- package/agent/commands/acp.plan.md +552 -0
- package/agent/commands/acp.proceed.md +111 -86
- package/agent/commands/acp.project-create.md +672 -0
- package/agent/commands/acp.project-list.md +224 -0
- package/agent/commands/acp.project-set.md +226 -0
- package/agent/commands/acp.report.md +2 -0
- package/agent/commands/acp.resume.md +237 -0
- package/agent/commands/acp.sync.md +55 -15
- package/agent/commands/acp.task-create.md +390 -0
- package/agent/commands/acp.validate.md +61 -10
- package/agent/commands/acp.version-check-for-updates.md +5 -5
- package/agent/commands/acp.version-check.md +6 -6
- package/agent/commands/acp.version-update.md +6 -6
- package/agent/commands/command.template.md +43 -0
- package/agent/commands/git.commit.md +5 -3
- package/agent/design/soft-delete-system.md +291 -0
- package/agent/manifest.template.yaml +13 -0
- package/agent/milestones/milestone-13-soft-delete-system.md +306 -0
- package/agent/package.template.yaml +36 -0
- package/agent/progress.template.yaml +3 -0
- package/agent/progress.yaml +238 -6
- package/agent/scripts/acp.common.sh +1536 -0
- package/agent/scripts/{install.sh → acp.install.sh} +82 -26
- package/agent/scripts/acp.package-create.sh +925 -0
- package/agent/scripts/acp.package-info.sh +270 -0
- package/agent/scripts/acp.package-install.sh +596 -0
- package/agent/scripts/acp.package-list.sh +263 -0
- package/agent/scripts/acp.package-publish.sh +420 -0
- package/agent/scripts/acp.package-remove.sh +272 -0
- package/agent/scripts/acp.package-search.sh +156 -0
- package/agent/scripts/acp.package-update.sh +438 -0
- package/agent/scripts/acp.package-validate.sh +855 -0
- package/agent/scripts/acp.project-list.sh +121 -0
- package/agent/scripts/acp.project-set.sh +138 -0
- package/agent/scripts/{uninstall.sh → acp.uninstall.sh} +25 -15
- package/agent/scripts/{check-for-updates.sh → acp.version-check-for-updates.sh} +24 -14
- package/agent/scripts/{version.sh → acp.version-check.sh} +20 -8
- package/agent/scripts/{update.sh → acp.version-update.sh} +44 -25
- package/agent/scripts/acp.yaml-parser.sh +853 -0
- package/agent/scripts/acp.yaml-validate.sh +205 -0
- package/agent/tasks/task-68-fix-missing-space-properties.md +192 -0
- package/agent/tasks/task-69-add-comprehensive-tool-debugging.md +454 -0
- package/agent/tasks/task-70-add-soft-delete-schema-fields.md +165 -0
- package/agent/tasks/task-71-implement-delete-confirmation-flow.md +257 -0
- package/agent/tasks/task-72-add-deleted-filter-to-search-tools.md +18 -0
- package/agent/tasks/task-73-update-relationship-handling.md +18 -0
- package/agent/tasks/task-74-add-unit-tests-soft-delete.md +18 -0
- package/agent/tasks/task-75-update-documentation-changelog.md +26 -0
- package/dist/config.d.ts +18 -0
- package/dist/server-factory.js +788 -355
- package/dist/server.js +788 -355
- package/dist/tools/delete-memory.d.ts +5 -30
- package/dist/tools/find-similar.d.ts +8 -1
- package/dist/tools/query-memory.d.ts +8 -1
- package/dist/tools/search-memory.d.ts +6 -0
- package/dist/tools/search-relationship.d.ts +8 -1
- package/dist/types/memory.d.ts +8 -0
- package/dist/types/space-memory.d.ts +3 -0
- package/dist/utils/debug.d.ts +52 -0
- package/dist/utils/debug.spec.d.ts +5 -0
- package/dist/utils/weaviate-filters.d.ts +19 -0
- package/dist/weaviate/client.d.ts +1 -1
- package/package.json +1 -1
- package/src/config.ts +33 -0
- package/src/tools/confirm.ts +113 -8
- package/src/tools/create-relationship.ts +14 -1
- package/src/tools/delete-memory.ts +91 -63
- package/src/tools/find-similar.ts +30 -5
- package/src/tools/publish.ts +19 -1
- package/src/tools/query-memory.ts +18 -5
- package/src/tools/query-space.ts +36 -3
- package/src/tools/search-memory.ts +18 -5
- package/src/tools/search-relationship.ts +19 -5
- package/src/tools/search-space.ts +36 -3
- package/src/tools/update-memory.ts +8 -0
- package/src/types/memory.ts +11 -0
- package/src/types/space-memory.ts +5 -0
- package/src/utils/debug.spec.ts +257 -0
- package/src/utils/debug.ts +138 -0
- package/src/utils/weaviate-filters.ts +28 -1
- package/src/weaviate/client.ts +47 -3
- package/src/weaviate/schema.ts +17 -0
- package/src/weaviate/space-schema.spec.ts +5 -2
- package/src/weaviate/space-schema.ts +17 -5
package/dist/server.js
CHANGED
|
@@ -479,12 +479,36 @@ function validateConfig() {
|
|
|
479
479
|
});
|
|
480
480
|
});
|
|
481
481
|
}
|
|
482
|
-
var import_dotenv, config;
|
|
482
|
+
var import_dotenv, debugConfig, config;
|
|
483
483
|
var init_config = __esm({
|
|
484
484
|
"src/config.ts"() {
|
|
485
485
|
"use strict";
|
|
486
486
|
import_dotenv = __toESM(require_main(), 1);
|
|
487
487
|
import_dotenv.default.config();
|
|
488
|
+
debugConfig = {
|
|
489
|
+
level: (() => {
|
|
490
|
+
const level = process.env.REMEMBER_MCP_DEBUG_LEVEL?.toUpperCase();
|
|
491
|
+
switch (level) {
|
|
492
|
+
case "TRACE":
|
|
493
|
+
return 5 /* TRACE */;
|
|
494
|
+
case "DEBUG":
|
|
495
|
+
return 4 /* DEBUG */;
|
|
496
|
+
case "INFO":
|
|
497
|
+
return 3 /* INFO */;
|
|
498
|
+
case "WARN":
|
|
499
|
+
return 2 /* WARN */;
|
|
500
|
+
case "ERROR":
|
|
501
|
+
return 1 /* ERROR */;
|
|
502
|
+
case "NONE":
|
|
503
|
+
return 0 /* NONE */;
|
|
504
|
+
default:
|
|
505
|
+
return 0 /* NONE */;
|
|
506
|
+
}
|
|
507
|
+
})(),
|
|
508
|
+
enabled: (level) => {
|
|
509
|
+
return debugConfig.level >= level;
|
|
510
|
+
}
|
|
511
|
+
};
|
|
488
512
|
config = {
|
|
489
513
|
// Weaviate
|
|
490
514
|
weaviate: {
|
|
@@ -538,6 +562,103 @@ import {
|
|
|
538
562
|
init_config();
|
|
539
563
|
init_logger();
|
|
540
564
|
import weaviate from "weaviate-client";
|
|
565
|
+
|
|
566
|
+
// src/utils/debug.ts
|
|
567
|
+
init_config();
|
|
568
|
+
init_logger();
|
|
569
|
+
var DebugLogger = class {
|
|
570
|
+
context;
|
|
571
|
+
constructor(context) {
|
|
572
|
+
this.context = context;
|
|
573
|
+
}
|
|
574
|
+
trace(message, data) {
|
|
575
|
+
if (debugConfig.enabled(5 /* TRACE */)) {
|
|
576
|
+
logger.debug(`[TRACE] ${message}`, {
|
|
577
|
+
...this.context,
|
|
578
|
+
...data,
|
|
579
|
+
debugLevel: "TRACE"
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
debug(message, data) {
|
|
584
|
+
if (debugConfig.enabled(4 /* DEBUG */)) {
|
|
585
|
+
logger.debug(`[DEBUG] ${message}`, {
|
|
586
|
+
...this.context,
|
|
587
|
+
...data,
|
|
588
|
+
debugLevel: "DEBUG"
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
info(message, data) {
|
|
593
|
+
if (debugConfig.enabled(3 /* INFO */)) {
|
|
594
|
+
logger.info(`[INFO] ${message}`, {
|
|
595
|
+
...this.context,
|
|
596
|
+
...data,
|
|
597
|
+
debugLevel: "INFO"
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
warn(message, data) {
|
|
602
|
+
if (debugConfig.enabled(2 /* WARN */)) {
|
|
603
|
+
logger.warn(`[WARN] ${message}`, {
|
|
604
|
+
...this.context,
|
|
605
|
+
...data,
|
|
606
|
+
debugLevel: "WARN"
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
error(message, data) {
|
|
611
|
+
if (debugConfig.enabled(1 /* ERROR */)) {
|
|
612
|
+
logger.error(`[ERROR] ${message}`, {
|
|
613
|
+
...this.context,
|
|
614
|
+
...data,
|
|
615
|
+
debugLevel: "ERROR"
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Dump full object (TRACE only)
|
|
621
|
+
* Use with caution - may expose sensitive data
|
|
622
|
+
*/
|
|
623
|
+
dump(label, obj) {
|
|
624
|
+
if (debugConfig.enabled(5 /* TRACE */)) {
|
|
625
|
+
logger.debug(`[DUMP] ${label}`, {
|
|
626
|
+
...this.context,
|
|
627
|
+
dump: JSON.stringify(obj, null, 2),
|
|
628
|
+
debugLevel: "TRACE"
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Time an async operation (DEBUG and above)
|
|
634
|
+
* Logs start, completion, and duration
|
|
635
|
+
*/
|
|
636
|
+
async time(label, fn) {
|
|
637
|
+
if (!debugConfig.enabled(4 /* DEBUG */)) {
|
|
638
|
+
return fn();
|
|
639
|
+
}
|
|
640
|
+
const start = Date.now();
|
|
641
|
+
this.debug(`${label} - Starting`);
|
|
642
|
+
try {
|
|
643
|
+
const result = await fn();
|
|
644
|
+
const duration = Date.now() - start;
|
|
645
|
+
this.debug(`${label} - Completed`, { durationMs: duration });
|
|
646
|
+
return result;
|
|
647
|
+
} catch (error) {
|
|
648
|
+
const duration = Date.now() - start;
|
|
649
|
+
this.error(`${label} - Failed`, {
|
|
650
|
+
durationMs: duration,
|
|
651
|
+
error: error instanceof Error ? error.message : String(error)
|
|
652
|
+
});
|
|
653
|
+
throw error;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
};
|
|
657
|
+
function createDebugLogger(context) {
|
|
658
|
+
return new DebugLogger(context);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// src/weaviate/client.ts
|
|
541
662
|
var client = null;
|
|
542
663
|
async function initWeaviateClient() {
|
|
543
664
|
if (client) {
|
|
@@ -660,20 +781,56 @@ var ALL_MEMORY_PROPERTIES = [
|
|
|
660
781
|
// Comment/threading fields
|
|
661
782
|
"parent_id",
|
|
662
783
|
"thread_root_id",
|
|
663
|
-
"moderation_flags"
|
|
784
|
+
"moderation_flags",
|
|
785
|
+
// Space/publishing fields (for Memory_public collection)
|
|
786
|
+
"spaces",
|
|
787
|
+
"space_id",
|
|
788
|
+
"author_id",
|
|
789
|
+
"ghost_id",
|
|
790
|
+
"attribution",
|
|
791
|
+
"published_at",
|
|
792
|
+
"discovery_count",
|
|
793
|
+
"space_memory_id",
|
|
794
|
+
// Soft delete fields
|
|
795
|
+
"deleted_at",
|
|
796
|
+
"deleted_by",
|
|
797
|
+
"deletion_reason"
|
|
664
798
|
];
|
|
665
799
|
async function fetchMemoryWithAllProperties(collection, memoryId) {
|
|
800
|
+
const debug = createDebugLogger({
|
|
801
|
+
tool: "weaviate-client",
|
|
802
|
+
operation: "fetchMemoryWithAllProperties"
|
|
803
|
+
});
|
|
804
|
+
debug.debug("Fetching memory", {
|
|
805
|
+
memoryId,
|
|
806
|
+
collectionName: collection.name,
|
|
807
|
+
propertyCount: ALL_MEMORY_PROPERTIES.length
|
|
808
|
+
});
|
|
666
809
|
try {
|
|
667
|
-
|
|
668
|
-
|
|
810
|
+
const result = await debug.time("Fetch with all properties", async () => {
|
|
811
|
+
return await collection.query.fetchObjectById(memoryId, {
|
|
812
|
+
returnProperties: ALL_MEMORY_PROPERTIES
|
|
813
|
+
});
|
|
814
|
+
});
|
|
815
|
+
debug.trace("Fetch result", {
|
|
816
|
+
found: !!result,
|
|
817
|
+
propertyCount: result?.properties ? Object.keys(result.properties).length : 0,
|
|
818
|
+
hasSpaces: !!result?.properties?.spaces,
|
|
819
|
+
hasAuthorId: !!result?.properties?.author_id
|
|
669
820
|
});
|
|
821
|
+
return result;
|
|
670
822
|
} catch (error) {
|
|
823
|
+
debug.warn("Fetch with all properties failed, falling back", {
|
|
824
|
+
error: error instanceof Error ? error.message : String(error)
|
|
825
|
+
});
|
|
671
826
|
logger.warn("Failed to fetch with all properties, falling back to unspecified fetch", {
|
|
672
827
|
module: "weaviate-client",
|
|
673
828
|
memoryId,
|
|
674
829
|
error: error instanceof Error ? error.message : String(error)
|
|
675
830
|
});
|
|
676
|
-
return await
|
|
831
|
+
return await debug.time("Fetch without property specification", async () => {
|
|
832
|
+
return await collection.query.fetchObjectById(memoryId);
|
|
833
|
+
});
|
|
677
834
|
}
|
|
678
835
|
}
|
|
679
836
|
|
|
@@ -975,6 +1132,22 @@ async function createMemoryCollection(userId) {
|
|
|
975
1132
|
name: "moderation_flags",
|
|
976
1133
|
dataType: "text[]",
|
|
977
1134
|
description: 'Per-space moderation flags (format: "{space_id}:{flag_type}")'
|
|
1135
|
+
},
|
|
1136
|
+
// Soft delete fields
|
|
1137
|
+
{
|
|
1138
|
+
name: "deleted_at",
|
|
1139
|
+
dataType: "date",
|
|
1140
|
+
description: "Timestamp when memory was soft-deleted (null = not deleted)"
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
name: "deleted_by",
|
|
1144
|
+
dataType: "text",
|
|
1145
|
+
description: "User ID who deleted the memory"
|
|
1146
|
+
},
|
|
1147
|
+
{
|
|
1148
|
+
name: "deletion_reason",
|
|
1149
|
+
dataType: "text",
|
|
1150
|
+
description: "Optional reason for deletion"
|
|
978
1151
|
}
|
|
979
1152
|
]
|
|
980
1153
|
});
|
|
@@ -1678,6 +1851,14 @@ function combineFiltersWithOr(filters) {
|
|
|
1678
1851
|
}
|
|
1679
1852
|
return Filters.or(...validFilters);
|
|
1680
1853
|
}
|
|
1854
|
+
function buildDeletedFilter(collection, deletedFilter = "exclude") {
|
|
1855
|
+
if (deletedFilter === "exclude") {
|
|
1856
|
+
return collection.filter.byProperty("deleted_at").isNull(true);
|
|
1857
|
+
} else if (deletedFilter === "only") {
|
|
1858
|
+
return collection.filter.byProperty("deleted_at").isNull(false);
|
|
1859
|
+
}
|
|
1860
|
+
return null;
|
|
1861
|
+
}
|
|
1681
1862
|
|
|
1682
1863
|
// src/tools/search-memory.ts
|
|
1683
1864
|
var searchMemoryTool = {
|
|
@@ -1778,6 +1959,12 @@ var searchMemoryTool = {
|
|
|
1778
1959
|
type: "boolean",
|
|
1779
1960
|
description: "Include relationships in results. Default: true (searches both memories and relationships)",
|
|
1780
1961
|
default: true
|
|
1962
|
+
},
|
|
1963
|
+
deleted_filter: {
|
|
1964
|
+
type: "string",
|
|
1965
|
+
enum: ["exclude", "include", "only"],
|
|
1966
|
+
default: "exclude",
|
|
1967
|
+
description: 'Filter deleted memories: "exclude" (default, hide deleted), "include" (show all), "only" (show only deleted)'
|
|
1781
1968
|
}
|
|
1782
1969
|
},
|
|
1783
1970
|
required: ["query"]
|
|
@@ -1798,19 +1985,22 @@ async function handleSearchMemory(args, userId) {
|
|
|
1798
1985
|
const alpha = args.alpha ?? 0.7;
|
|
1799
1986
|
const limit = args.limit ?? 10;
|
|
1800
1987
|
const offset = args.offset ?? 0;
|
|
1801
|
-
const
|
|
1988
|
+
const deletedFilter = buildDeletedFilter(collection, args.deleted_filter || "exclude");
|
|
1989
|
+
const searchFilters = includeRelationships ? buildCombinedSearchFilters(collection, args.filters) : buildMemoryOnlyFilters(collection, args.filters);
|
|
1990
|
+
const combinedFilters = combineFiltersWithAnd([deletedFilter, searchFilters].filter((f) => f !== null));
|
|
1802
1991
|
const searchOptions = {
|
|
1803
1992
|
alpha,
|
|
1804
1993
|
limit: limit + offset
|
|
1805
1994
|
// Get extra for offset
|
|
1806
1995
|
};
|
|
1807
|
-
if (
|
|
1808
|
-
searchOptions.filters =
|
|
1996
|
+
if (combinedFilters) {
|
|
1997
|
+
searchOptions.filters = combinedFilters;
|
|
1809
1998
|
}
|
|
1810
1999
|
logger.info("Weaviate query", {
|
|
1811
2000
|
query: args.query,
|
|
1812
2001
|
searchOptions: JSON.stringify(searchOptions, null, 2),
|
|
1813
|
-
hasFilters: !!
|
|
2002
|
+
hasFilters: !!combinedFilters,
|
|
2003
|
+
deletedFilter: args.deleted_filter || "exclude"
|
|
1814
2004
|
});
|
|
1815
2005
|
const results = await collection.query.hybrid(args.query, searchOptions);
|
|
1816
2006
|
const paginatedResults = results.objects.slice(offset);
|
|
@@ -1854,95 +2044,360 @@ async function handleSearchMemory(args, userId) {
|
|
|
1854
2044
|
}
|
|
1855
2045
|
|
|
1856
2046
|
// src/tools/delete-memory.ts
|
|
2047
|
+
import { Filters as Filters2 } from "weaviate-client";
|
|
2048
|
+
|
|
2049
|
+
// src/services/confirmation-token.service.ts
|
|
2050
|
+
import { randomUUID } from "crypto";
|
|
1857
2051
|
init_logger();
|
|
1858
|
-
var
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
2052
|
+
var ConfirmationTokenService = class {
|
|
2053
|
+
EXPIRY_MINUTES = 5;
|
|
2054
|
+
/**
|
|
2055
|
+
* Create a new confirmation request
|
|
2056
|
+
*
|
|
2057
|
+
* @param userId - User ID who initiated the request
|
|
2058
|
+
* @param action - Action type (e.g., 'publish_memory')
|
|
2059
|
+
* @param payload - Data to store with the request
|
|
2060
|
+
* @param targetCollection - Optional target collection (e.g., 'the_void')
|
|
2061
|
+
* @returns Request ID and token
|
|
2062
|
+
*/
|
|
2063
|
+
async createRequest(userId, action, payload, targetCollection) {
|
|
2064
|
+
try {
|
|
2065
|
+
const token = randomUUID();
|
|
2066
|
+
const now = /* @__PURE__ */ new Date();
|
|
2067
|
+
const expiresAt = new Date(now.getTime() + this.EXPIRY_MINUTES * 60 * 1e3);
|
|
2068
|
+
const request = {
|
|
2069
|
+
user_id: userId,
|
|
2070
|
+
token,
|
|
2071
|
+
action,
|
|
2072
|
+
target_collection: targetCollection,
|
|
2073
|
+
payload,
|
|
2074
|
+
created_at: now.toISOString(),
|
|
2075
|
+
expires_at: expiresAt.toISOString(),
|
|
2076
|
+
status: "pending"
|
|
2077
|
+
};
|
|
2078
|
+
const collectionPath = `users/${userId}/requests`;
|
|
2079
|
+
logger.info("Creating confirmation request", {
|
|
2080
|
+
service: "ConfirmationTokenService",
|
|
2081
|
+
userId,
|
|
2082
|
+
action,
|
|
2083
|
+
targetCollection,
|
|
2084
|
+
collectionPath,
|
|
2085
|
+
payloadKeys: Object.keys(payload)
|
|
2086
|
+
});
|
|
2087
|
+
logger.debug("Calling Firestore addDocument", {
|
|
2088
|
+
service: "ConfirmationTokenService",
|
|
2089
|
+
collectionPath
|
|
2090
|
+
});
|
|
2091
|
+
const docRef = await addDocument(collectionPath, request);
|
|
2092
|
+
logger.debug("Firestore addDocument returned", {
|
|
2093
|
+
service: "ConfirmationTokenService",
|
|
2094
|
+
hasDocRef: !!docRef,
|
|
2095
|
+
hasId: !!docRef?.id,
|
|
2096
|
+
docRefId: docRef?.id
|
|
2097
|
+
});
|
|
2098
|
+
if (!docRef) {
|
|
2099
|
+
const error = new Error("Firestore addDocument returned null/undefined");
|
|
2100
|
+
logger.error("CRITICAL: addDocument returned null", {
|
|
2101
|
+
service: "ConfirmationTokenService",
|
|
2102
|
+
userId,
|
|
2103
|
+
collectionPath
|
|
2104
|
+
});
|
|
2105
|
+
throw error;
|
|
1880
2106
|
}
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
returnProperties: ["user_id", "doc_type", "relationships"]
|
|
1891
|
-
});
|
|
1892
|
-
if (!memory) {
|
|
1893
|
-
throw new Error(`Memory not found: ${args.memory_id}`);
|
|
1894
|
-
}
|
|
1895
|
-
if (memory.properties.user_id !== userId) {
|
|
1896
|
-
throw new Error("Unauthorized: Cannot delete another user's memory");
|
|
1897
|
-
}
|
|
1898
|
-
if (memory.properties.doc_type !== "memory") {
|
|
1899
|
-
throw new Error("Cannot delete relationships using this tool. Use remember_delete_relationship instead.");
|
|
1900
|
-
}
|
|
1901
|
-
let relationshipsDeleted = 0;
|
|
1902
|
-
if (args.delete_relationships && memory.properties.relationships) {
|
|
1903
|
-
const relationshipIds = memory.properties.relationships;
|
|
1904
|
-
for (const relId of relationshipIds) {
|
|
1905
|
-
try {
|
|
1906
|
-
await collection.data.deleteById(relId);
|
|
1907
|
-
relationshipsDeleted++;
|
|
1908
|
-
} catch (error) {
|
|
1909
|
-
logger.warn(`Failed to delete relationship ${relId}:`, error);
|
|
1910
|
-
}
|
|
2107
|
+
if (!docRef.id) {
|
|
2108
|
+
const error = new Error("Firestore addDocument returned docRef without ID");
|
|
2109
|
+
logger.error("CRITICAL: docRef has no ID", {
|
|
2110
|
+
service: "ConfirmationTokenService",
|
|
2111
|
+
userId,
|
|
2112
|
+
collectionPath,
|
|
2113
|
+
docRef
|
|
2114
|
+
});
|
|
2115
|
+
throw error;
|
|
1911
2116
|
}
|
|
2117
|
+
logger.info("Confirmation request created successfully", {
|
|
2118
|
+
service: "ConfirmationTokenService",
|
|
2119
|
+
requestId: docRef.id,
|
|
2120
|
+
token,
|
|
2121
|
+
expiresAt: request.expires_at
|
|
2122
|
+
});
|
|
2123
|
+
return { requestId: docRef.id, token };
|
|
2124
|
+
} catch (error) {
|
|
2125
|
+
logger.error("Failed to create confirmation request", {
|
|
2126
|
+
service: "ConfirmationTokenService",
|
|
2127
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2128
|
+
stack: error instanceof Error ? error.stack : void 0,
|
|
2129
|
+
userId,
|
|
2130
|
+
action,
|
|
2131
|
+
collectionPath: `users/${userId}/requests`
|
|
2132
|
+
});
|
|
2133
|
+
throw error;
|
|
1912
2134
|
}
|
|
1913
|
-
|
|
1914
|
-
|
|
2135
|
+
}
|
|
2136
|
+
/**
|
|
2137
|
+
* Validate and retrieve a confirmation request
|
|
2138
|
+
*
|
|
2139
|
+
* @param userId - User ID
|
|
2140
|
+
* @param token - Confirmation token
|
|
2141
|
+
* @returns Request with request_id if valid, null otherwise
|
|
2142
|
+
*/
|
|
2143
|
+
async validateToken(userId, token) {
|
|
2144
|
+
const collectionPath = `users/${userId}/requests`;
|
|
2145
|
+
logger.debug("Validating confirmation token", {
|
|
2146
|
+
service: "ConfirmationTokenService",
|
|
1915
2147
|
userId,
|
|
1916
|
-
|
|
1917
|
-
|
|
2148
|
+
token,
|
|
2149
|
+
collectionPath
|
|
1918
2150
|
});
|
|
1919
|
-
const
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
2151
|
+
const queryOptions = {
|
|
2152
|
+
where: [
|
|
2153
|
+
{ field: "token", op: "==", value: token },
|
|
2154
|
+
{ field: "status", op: "==", value: "pending" }
|
|
2155
|
+
],
|
|
2156
|
+
limit: 1
|
|
1924
2157
|
};
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
2158
|
+
const results = await queryDocuments(collectionPath, queryOptions);
|
|
2159
|
+
logger.debug("Token query results", {
|
|
2160
|
+
service: "ConfirmationTokenService",
|
|
2161
|
+
resultsFound: results.length,
|
|
2162
|
+
hasResults: results.length > 0
|
|
2163
|
+
});
|
|
2164
|
+
if (results.length === 0) {
|
|
2165
|
+
logger.info("Token not found or not pending", {
|
|
2166
|
+
service: "ConfirmationTokenService",
|
|
2167
|
+
userId
|
|
2168
|
+
});
|
|
2169
|
+
return null;
|
|
2170
|
+
}
|
|
2171
|
+
const doc = results[0];
|
|
2172
|
+
const request = doc.data;
|
|
2173
|
+
logger.info("Confirmation request found", {
|
|
2174
|
+
service: "ConfirmationTokenService",
|
|
2175
|
+
requestId: doc.id,
|
|
2176
|
+
action: request.action,
|
|
2177
|
+
status: request.status,
|
|
2178
|
+
expiresAt: request.expires_at
|
|
1933
2179
|
});
|
|
2180
|
+
const expiresAt = new Date(request.expires_at);
|
|
2181
|
+
if (expiresAt.getTime() < Date.now()) {
|
|
2182
|
+
logger.info("Token expired", {
|
|
2183
|
+
service: "ConfirmationTokenService",
|
|
2184
|
+
requestId: doc.id,
|
|
2185
|
+
expiresAt: request.expires_at
|
|
2186
|
+
});
|
|
2187
|
+
await this.updateStatus(userId, doc.id, "expired");
|
|
2188
|
+
return null;
|
|
2189
|
+
}
|
|
2190
|
+
return {
|
|
2191
|
+
...request,
|
|
2192
|
+
request_id: doc.id
|
|
2193
|
+
};
|
|
1934
2194
|
}
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
2195
|
+
/**
|
|
2196
|
+
* Confirm a request
|
|
2197
|
+
*
|
|
2198
|
+
* @param userId - User ID
|
|
2199
|
+
* @param token - Confirmation token
|
|
2200
|
+
* @returns Confirmed request if valid, null otherwise
|
|
2201
|
+
*/
|
|
2202
|
+
async confirmRequest(userId, token) {
|
|
2203
|
+
const request = await this.validateToken(userId, token);
|
|
2204
|
+
if (!request) {
|
|
2205
|
+
return null;
|
|
2206
|
+
}
|
|
2207
|
+
await this.updateStatus(userId, request.request_id, "confirmed");
|
|
2208
|
+
return {
|
|
2209
|
+
...request,
|
|
2210
|
+
status: "confirmed",
|
|
2211
|
+
confirmed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
2212
|
+
};
|
|
2213
|
+
}
|
|
2214
|
+
/**
|
|
2215
|
+
* Deny a request
|
|
2216
|
+
*
|
|
2217
|
+
* @param userId - User ID
|
|
2218
|
+
* @param token - Confirmation token
|
|
2219
|
+
* @returns True if denied successfully, false otherwise
|
|
2220
|
+
*/
|
|
2221
|
+
async denyRequest(userId, token) {
|
|
2222
|
+
const request = await this.validateToken(userId, token);
|
|
2223
|
+
if (!request) {
|
|
2224
|
+
return false;
|
|
2225
|
+
}
|
|
2226
|
+
await this.updateStatus(userId, request.request_id, "denied");
|
|
2227
|
+
return true;
|
|
2228
|
+
}
|
|
2229
|
+
/**
|
|
2230
|
+
* Retract a request
|
|
2231
|
+
*
|
|
2232
|
+
* @param userId - User ID
|
|
2233
|
+
* @param token - Confirmation token
|
|
2234
|
+
* @returns True if retracted successfully, false otherwise
|
|
2235
|
+
*/
|
|
2236
|
+
async retractRequest(userId, token) {
|
|
2237
|
+
const request = await this.validateToken(userId, token);
|
|
2238
|
+
if (!request) {
|
|
2239
|
+
return false;
|
|
2240
|
+
}
|
|
2241
|
+
await this.updateStatus(userId, request.request_id, "retracted");
|
|
2242
|
+
return true;
|
|
2243
|
+
}
|
|
2244
|
+
/**
|
|
2245
|
+
* Update request status
|
|
2246
|
+
*
|
|
2247
|
+
* @param userId - User ID
|
|
2248
|
+
* @param requestId - Request document ID
|
|
2249
|
+
* @param status - New status
|
|
2250
|
+
*/
|
|
2251
|
+
async updateStatus(userId, requestId, status) {
|
|
2252
|
+
const collectionPath = `users/${userId}/requests`;
|
|
2253
|
+
const updateData = {
|
|
2254
|
+
status
|
|
2255
|
+
};
|
|
2256
|
+
if (status === "confirmed") {
|
|
2257
|
+
updateData.confirmed_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
2258
|
+
}
|
|
2259
|
+
await updateDocument(collectionPath, requestId, updateData);
|
|
2260
|
+
}
|
|
2261
|
+
/**
|
|
2262
|
+
* Clean up expired requests (optional - Firestore TTL handles deletion)
|
|
2263
|
+
*
|
|
2264
|
+
* Note: Configure Firestore TTL policy on 'requests' collection group
|
|
2265
|
+
* with 'expires_at' field for automatic deletion within 24 hours.
|
|
2266
|
+
*
|
|
2267
|
+
* This method is optional for immediate cleanup if needed.
|
|
2268
|
+
*
|
|
2269
|
+
* @returns Count of deleted requests
|
|
2270
|
+
*/
|
|
2271
|
+
async cleanupExpired() {
|
|
2272
|
+
logger.warn("cleanupExpired not implemented - relying on Firestore TTL", {
|
|
2273
|
+
service: "ConfirmationTokenService",
|
|
2274
|
+
note: "Configure Firestore TTL policy on requests collection group"
|
|
2275
|
+
});
|
|
2276
|
+
return 0;
|
|
2277
|
+
}
|
|
2278
|
+
};
|
|
2279
|
+
var confirmationTokenService = new ConfirmationTokenService();
|
|
2280
|
+
|
|
2281
|
+
// src/tools/delete-memory.ts
|
|
2282
|
+
init_logger();
|
|
2283
|
+
var deleteMemoryTool = {
|
|
2284
|
+
name: "remember_delete_memory",
|
|
2285
|
+
description: `Request to delete a memory. Requires confirmation via remember_confirm.
|
|
2286
|
+
|
|
2287
|
+
\u26A0\uFE0F **IMPORTANT**: This is a two-step process:
|
|
2288
|
+
1. Call remember_delete_memory to request deletion (returns token)
|
|
2289
|
+
2. User must confirm via remember_confirm with the token
|
|
2290
|
+
|
|
2291
|
+
The memory will be soft-deleted (marked as deleted but not removed from database).
|
|
2292
|
+
|
|
2293
|
+
Examples:
|
|
2294
|
+
- "Delete that old camping note"
|
|
2295
|
+
- "Remove the recipe I saved yesterday"
|
|
2296
|
+
`,
|
|
2297
|
+
inputSchema: {
|
|
2298
|
+
type: "object",
|
|
2299
|
+
properties: {
|
|
2300
|
+
memory_id: {
|
|
2301
|
+
type: "string",
|
|
2302
|
+
description: "ID of the memory to delete"
|
|
2303
|
+
},
|
|
2304
|
+
reason: {
|
|
2305
|
+
type: "string",
|
|
2306
|
+
description: "Optional reason for deletion"
|
|
2307
|
+
}
|
|
2308
|
+
},
|
|
2309
|
+
required: ["memory_id"]
|
|
2310
|
+
}
|
|
2311
|
+
};
|
|
2312
|
+
async function handleDeleteMemory(args, userId) {
|
|
2313
|
+
try {
|
|
2314
|
+
logger.info("Requesting memory deletion", {
|
|
2315
|
+
userId,
|
|
2316
|
+
memoryId: args.memory_id,
|
|
2317
|
+
hasReason: !!args.reason
|
|
2318
|
+
});
|
|
2319
|
+
const { memory_id, reason } = args;
|
|
2320
|
+
const client2 = getWeaviateClient();
|
|
2321
|
+
const collectionName = `Memory_${sanitizeUserId(userId)}`;
|
|
2322
|
+
const collection = client2.collections.get(collectionName);
|
|
2323
|
+
const memory = await fetchMemoryWithAllProperties(collection, memory_id);
|
|
2324
|
+
if (!memory) {
|
|
2325
|
+
throw new Error(`Memory not found: ${memory_id}`);
|
|
2326
|
+
}
|
|
2327
|
+
if (memory.properties.user_id !== userId) {
|
|
2328
|
+
throw new Error(`Cannot delete memory: not owned by user ${userId}`);
|
|
2329
|
+
}
|
|
2330
|
+
if (memory.properties.doc_type !== "memory") {
|
|
2331
|
+
throw new Error("Cannot delete relationships using this tool. Use remember_delete_relationship instead.");
|
|
2332
|
+
}
|
|
2333
|
+
if (memory.properties.deleted_at) {
|
|
2334
|
+
throw new Error(`Memory ${memory_id} is already deleted`);
|
|
2335
|
+
}
|
|
2336
|
+
const relationshipsResult = await collection.query.fetchObjects({
|
|
2337
|
+
filters: Filters2.and(
|
|
2338
|
+
collection.filter.byProperty("doc_type").equal("relationship"),
|
|
2339
|
+
collection.filter.byProperty("memory_ids").containsAny([memory_id])
|
|
2340
|
+
),
|
|
2341
|
+
limit: 100
|
|
2342
|
+
});
|
|
2343
|
+
const orphanedRelationships = relationshipsResult.objects.map((r) => r.uuid);
|
|
2344
|
+
logger.info("Found relationships to orphan", {
|
|
2345
|
+
userId,
|
|
2346
|
+
memoryId: memory_id,
|
|
2347
|
+
relationshipCount: orphanedRelationships.length
|
|
2348
|
+
});
|
|
2349
|
+
const { requestId, token } = await confirmationTokenService.createRequest(
|
|
2350
|
+
userId,
|
|
2351
|
+
"delete_memory",
|
|
2352
|
+
{
|
|
2353
|
+
memory_id,
|
|
2354
|
+
reason: reason || null
|
|
2355
|
+
}
|
|
2356
|
+
);
|
|
2357
|
+
const expiresAt = new Date(Date.now() + 5 * 60 * 1e3);
|
|
2358
|
+
logger.info("Delete confirmation token created", {
|
|
2359
|
+
userId,
|
|
2360
|
+
memoryId: memory_id,
|
|
2361
|
+
requestId,
|
|
2362
|
+
token,
|
|
2363
|
+
expiresAt: expiresAt.toISOString()
|
|
2364
|
+
});
|
|
2365
|
+
return JSON.stringify(
|
|
2366
|
+
{
|
|
2367
|
+
success: true,
|
|
2368
|
+
token,
|
|
2369
|
+
expires_at: expiresAt.toISOString(),
|
|
2370
|
+
preview: {
|
|
2371
|
+
memory_id,
|
|
2372
|
+
content: memory.properties.content?.substring(0, 200) + (memory.properties.content?.length > 200 ? "..." : ""),
|
|
2373
|
+
type: memory.properties.type,
|
|
2374
|
+
relationships_count: orphanedRelationships.length,
|
|
2375
|
+
will_orphan: orphanedRelationships
|
|
2376
|
+
},
|
|
2377
|
+
message: `Deletion requested. Use remember_confirm with token to complete deletion. Token expires in 5 minutes.`
|
|
2378
|
+
},
|
|
2379
|
+
null,
|
|
2380
|
+
2
|
|
2381
|
+
);
|
|
2382
|
+
} catch (error) {
|
|
2383
|
+
handleToolError(error, {
|
|
2384
|
+
toolName: "remember_delete_memory",
|
|
2385
|
+
userId,
|
|
2386
|
+
operation: "request delete",
|
|
2387
|
+
memoryId: args.memory_id
|
|
2388
|
+
});
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2392
|
+
// src/tools/update-memory.ts
|
|
2393
|
+
init_logger();
|
|
2394
|
+
var updateMemoryTool = {
|
|
2395
|
+
name: "remember_update_memory",
|
|
2396
|
+
description: `Update an existing memory with partial updates.
|
|
2397
|
+
|
|
2398
|
+
Supports updating any field except id, user_id, doc_type, created_at.
|
|
2399
|
+
Version number is automatically incremented and updated_at is set.
|
|
2400
|
+
Only provided fields are updated (partial updates supported).
|
|
1946
2401
|
|
|
1947
2402
|
Examples:
|
|
1948
2403
|
- "Update that camping note to add more details"
|
|
@@ -2037,6 +2492,10 @@ async function handleUpdateMemory(args, userId) {
|
|
|
2037
2492
|
if (existingMemory.properties.doc_type !== "memory") {
|
|
2038
2493
|
throw new Error("Cannot update relationships using this tool. Use remember_update_relationship instead.");
|
|
2039
2494
|
}
|
|
2495
|
+
if (existingMemory.properties.deleted_at) {
|
|
2496
|
+
const deletedAt = typeof existingMemory.properties.deleted_at === "string" ? existingMemory.properties.deleted_at : new Date(existingMemory.properties.deleted_at).toISOString();
|
|
2497
|
+
throw new Error(`Cannot update deleted memory: ${args.memory_id}. Memory was deleted on ${deletedAt}.`);
|
|
2498
|
+
}
|
|
2040
2499
|
const updates = {};
|
|
2041
2500
|
const updatedFields = [];
|
|
2042
2501
|
if (args.content !== void 0) {
|
|
@@ -2204,6 +2663,12 @@ var findSimilarTool = {
|
|
|
2204
2663
|
type: "boolean",
|
|
2205
2664
|
description: "Include relationships in results. Default: false",
|
|
2206
2665
|
default: false
|
|
2666
|
+
},
|
|
2667
|
+
deleted_filter: {
|
|
2668
|
+
type: "string",
|
|
2669
|
+
enum: ["exclude", "include", "only"],
|
|
2670
|
+
default: "exclude",
|
|
2671
|
+
description: 'Filter deleted memories: "exclude" (default, hide deleted), "include" (show all), "only" (show only deleted)'
|
|
2207
2672
|
}
|
|
2208
2673
|
}
|
|
2209
2674
|
}
|
|
@@ -2220,6 +2685,7 @@ async function handleFindSimilar(args, userId) {
|
|
|
2220
2685
|
const collection = getMemoryCollection(userId);
|
|
2221
2686
|
const limit = args.limit ?? 10;
|
|
2222
2687
|
const minSimilarity = args.min_similarity ?? 0.7;
|
|
2688
|
+
const deletedFilter = buildDeletedFilter(collection, args.deleted_filter || "exclude");
|
|
2223
2689
|
let results;
|
|
2224
2690
|
if (args.memory_id) {
|
|
2225
2691
|
const memory = await collection.query.fetchObjectById(args.memory_id, {
|
|
@@ -2234,20 +2700,28 @@ async function handleFindSimilar(args, userId) {
|
|
|
2234
2700
|
if (memory.properties.doc_type !== "memory") {
|
|
2235
2701
|
throw new Error("Can only find similar memories for memory documents, not relationships");
|
|
2236
2702
|
}
|
|
2237
|
-
|
|
2703
|
+
const searchOptions = {
|
|
2238
2704
|
limit: limit + 1,
|
|
2239
2705
|
// +1 to exclude the source memory itself
|
|
2240
2706
|
distance: 1 - minSimilarity,
|
|
2241
2707
|
// Convert similarity to distance
|
|
2242
2708
|
returnMetadata: ["distance"]
|
|
2243
|
-
}
|
|
2709
|
+
};
|
|
2710
|
+
if (deletedFilter) {
|
|
2711
|
+
searchOptions.filters = deletedFilter;
|
|
2712
|
+
}
|
|
2713
|
+
results = await collection.query.nearObject(args.memory_id, searchOptions);
|
|
2244
2714
|
results.objects = results.objects.filter((obj) => obj.uuid !== args.memory_id);
|
|
2245
2715
|
} else {
|
|
2246
|
-
|
|
2716
|
+
const searchOptions = {
|
|
2247
2717
|
limit,
|
|
2248
2718
|
distance: 1 - minSimilarity,
|
|
2249
2719
|
returnMetadata: ["distance"]
|
|
2250
|
-
}
|
|
2720
|
+
};
|
|
2721
|
+
if (deletedFilter) {
|
|
2722
|
+
searchOptions.filters = deletedFilter;
|
|
2723
|
+
}
|
|
2724
|
+
results = await collection.query.nearText(args.text, searchOptions);
|
|
2251
2725
|
}
|
|
2252
2726
|
if (!args.include_relationships) {
|
|
2253
2727
|
results.objects = results.objects.filter(
|
|
@@ -2394,6 +2868,12 @@ var queryMemoryTool = {
|
|
|
2394
2868
|
description: 'Output format: "detailed" (full objects) or "compact" (text summary). Default: detailed',
|
|
2395
2869
|
enum: ["detailed", "compact"],
|
|
2396
2870
|
default: "detailed"
|
|
2871
|
+
},
|
|
2872
|
+
deleted_filter: {
|
|
2873
|
+
type: "string",
|
|
2874
|
+
enum: ["exclude", "include", "only"],
|
|
2875
|
+
default: "exclude",
|
|
2876
|
+
description: 'Filter deleted memories: "exclude" (default, hide deleted), "include" (show all), "only" (show only deleted)'
|
|
2397
2877
|
}
|
|
2398
2878
|
},
|
|
2399
2879
|
required: ["query"]
|
|
@@ -2410,15 +2890,17 @@ async function handleQueryMemory(args, userId) {
|
|
|
2410
2890
|
const minRelevance = args.min_relevance ?? 0.6;
|
|
2411
2891
|
const includeContext = args.include_context ?? true;
|
|
2412
2892
|
const format = args.format ?? "detailed";
|
|
2413
|
-
const
|
|
2893
|
+
const deletedFilter = buildDeletedFilter(collection, args.deleted_filter || "exclude");
|
|
2894
|
+
const searchFilters = buildCombinedSearchFilters(collection, args.filters);
|
|
2895
|
+
const combinedFilters = combineFiltersWithAnd([deletedFilter, searchFilters].filter((f) => f !== null));
|
|
2414
2896
|
const searchOptions = {
|
|
2415
2897
|
limit,
|
|
2416
2898
|
distance: 1 - minRelevance,
|
|
2417
2899
|
// Convert relevance to distance
|
|
2418
2900
|
returnMetadata: ["distance"]
|
|
2419
2901
|
};
|
|
2420
|
-
if (
|
|
2421
|
-
searchOptions.filters =
|
|
2902
|
+
if (combinedFilters) {
|
|
2903
|
+
searchOptions.filters = combinedFilters;
|
|
2422
2904
|
}
|
|
2423
2905
|
const results = await collection.query.nearText(args.query, searchOptions);
|
|
2424
2906
|
const relevantMemories = results.objects.map((obj) => {
|
|
@@ -2549,7 +3031,7 @@ async function handleCreateRelationship(args, userId, context) {
|
|
|
2549
3031
|
args.memory_ids.map(async (memoryId) => {
|
|
2550
3032
|
try {
|
|
2551
3033
|
const memory = await collection.query.fetchObjectById(memoryId, {
|
|
2552
|
-
returnProperties: ["user_id", "doc_type", "relationships"]
|
|
3034
|
+
returnProperties: ["user_id", "doc_type", "relationships", "deleted_at"]
|
|
2553
3035
|
});
|
|
2554
3036
|
if (!memory) {
|
|
2555
3037
|
logger.warn("Memory not found", { userId, memoryId });
|
|
@@ -2571,6 +3053,15 @@ async function handleCreateRelationship(args, userId, context) {
|
|
|
2571
3053
|
});
|
|
2572
3054
|
return { memoryId, error: "Cannot create relationship with non-memory document" };
|
|
2573
3055
|
}
|
|
3056
|
+
if (memory.properties.deleted_at) {
|
|
3057
|
+
const deletedAt = typeof memory.properties.deleted_at === "string" ? memory.properties.deleted_at : new Date(memory.properties.deleted_at).toISOString();
|
|
3058
|
+
logger.warn("Attempt to create relationship with deleted memory", {
|
|
3059
|
+
userId,
|
|
3060
|
+
memoryId,
|
|
3061
|
+
deletedAt
|
|
3062
|
+
});
|
|
3063
|
+
return { memoryId, error: `Memory is deleted (deleted on ${deletedAt})` };
|
|
3064
|
+
}
|
|
2574
3065
|
return {
|
|
2575
3066
|
memoryId,
|
|
2576
3067
|
memory,
|
|
@@ -2817,7 +3308,7 @@ async function handleUpdateRelationship(args, userId) {
|
|
|
2817
3308
|
}
|
|
2818
3309
|
|
|
2819
3310
|
// src/tools/search-relationship.ts
|
|
2820
|
-
import { Filters as
|
|
3311
|
+
import { Filters as Filters3 } from "weaviate-client";
|
|
2821
3312
|
init_logger();
|
|
2822
3313
|
var searchRelationshipTool = {
|
|
2823
3314
|
name: "remember_search_relationship",
|
|
@@ -2871,6 +3362,12 @@ var searchRelationshipTool = {
|
|
|
2871
3362
|
type: "number",
|
|
2872
3363
|
description: "Offset for pagination (default: 0)",
|
|
2873
3364
|
minimum: 0
|
|
3365
|
+
},
|
|
3366
|
+
deleted_filter: {
|
|
3367
|
+
type: "string",
|
|
3368
|
+
enum: ["exclude", "include", "only"],
|
|
3369
|
+
default: "exclude",
|
|
3370
|
+
description: 'Filter deleted memories: "exclude" (default, hide deleted), "include" (show all), "only" (show only deleted)'
|
|
2874
3371
|
}
|
|
2875
3372
|
},
|
|
2876
3373
|
required: ["query"]
|
|
@@ -2886,7 +3383,11 @@ async function handleSearchRelationship(args, userId) {
|
|
|
2886
3383
|
const collection = getMemoryCollection(userId);
|
|
2887
3384
|
const limit = args.limit ?? 10;
|
|
2888
3385
|
const offset = args.offset ?? 0;
|
|
3386
|
+
const deletedFilter = buildDeletedFilter(collection, args.deleted_filter || "exclude");
|
|
2889
3387
|
const filterList = [];
|
|
3388
|
+
if (deletedFilter) {
|
|
3389
|
+
filterList.push(deletedFilter);
|
|
3390
|
+
}
|
|
2890
3391
|
filterList.push(
|
|
2891
3392
|
collection.filter.byProperty("doc_type").equal("relationship")
|
|
2892
3393
|
);
|
|
@@ -2899,7 +3400,7 @@ async function handleSearchRelationship(args, userId) {
|
|
|
2899
3400
|
const typeFilters = args.relationship_types.map(
|
|
2900
3401
|
(type) => collection.filter.byProperty("relationship_type").equal(type)
|
|
2901
3402
|
);
|
|
2902
|
-
filterList.push(
|
|
3403
|
+
filterList.push(Filters3.or(...typeFilters));
|
|
2903
3404
|
}
|
|
2904
3405
|
}
|
|
2905
3406
|
if (args.strength_min !== void 0) {
|
|
@@ -2917,7 +3418,7 @@ async function handleSearchRelationship(args, userId) {
|
|
|
2917
3418
|
collection.filter.byProperty("tags").containsAny(args.tags)
|
|
2918
3419
|
);
|
|
2919
3420
|
}
|
|
2920
|
-
const combinedFilters =
|
|
3421
|
+
const combinedFilters = combineFiltersWithAnd(filterList);
|
|
2921
3422
|
const searchOptions = {
|
|
2922
3423
|
alpha: 1,
|
|
2923
3424
|
// Pure semantic search for relationships
|
|
@@ -3519,238 +4020,6 @@ async function handleGetPreferences(args, userId) {
|
|
|
3519
4020
|
}
|
|
3520
4021
|
}
|
|
3521
4022
|
|
|
3522
|
-
// src/services/confirmation-token.service.ts
|
|
3523
|
-
import { randomUUID } from "crypto";
|
|
3524
|
-
init_logger();
|
|
3525
|
-
var ConfirmationTokenService = class {
|
|
3526
|
-
EXPIRY_MINUTES = 5;
|
|
3527
|
-
/**
|
|
3528
|
-
* Create a new confirmation request
|
|
3529
|
-
*
|
|
3530
|
-
* @param userId - User ID who initiated the request
|
|
3531
|
-
* @param action - Action type (e.g., 'publish_memory')
|
|
3532
|
-
* @param payload - Data to store with the request
|
|
3533
|
-
* @param targetCollection - Optional target collection (e.g., 'the_void')
|
|
3534
|
-
* @returns Request ID and token
|
|
3535
|
-
*/
|
|
3536
|
-
async createRequest(userId, action, payload, targetCollection) {
|
|
3537
|
-
try {
|
|
3538
|
-
const token = randomUUID();
|
|
3539
|
-
const now = /* @__PURE__ */ new Date();
|
|
3540
|
-
const expiresAt = new Date(now.getTime() + this.EXPIRY_MINUTES * 60 * 1e3);
|
|
3541
|
-
const request = {
|
|
3542
|
-
user_id: userId,
|
|
3543
|
-
token,
|
|
3544
|
-
action,
|
|
3545
|
-
target_collection: targetCollection,
|
|
3546
|
-
payload,
|
|
3547
|
-
created_at: now.toISOString(),
|
|
3548
|
-
expires_at: expiresAt.toISOString(),
|
|
3549
|
-
status: "pending"
|
|
3550
|
-
};
|
|
3551
|
-
const collectionPath = `users/${userId}/requests`;
|
|
3552
|
-
logger.info("Creating confirmation request", {
|
|
3553
|
-
service: "ConfirmationTokenService",
|
|
3554
|
-
userId,
|
|
3555
|
-
action,
|
|
3556
|
-
targetCollection,
|
|
3557
|
-
collectionPath,
|
|
3558
|
-
payloadKeys: Object.keys(payload)
|
|
3559
|
-
});
|
|
3560
|
-
logger.debug("Calling Firestore addDocument", {
|
|
3561
|
-
service: "ConfirmationTokenService",
|
|
3562
|
-
collectionPath
|
|
3563
|
-
});
|
|
3564
|
-
const docRef = await addDocument(collectionPath, request);
|
|
3565
|
-
logger.debug("Firestore addDocument returned", {
|
|
3566
|
-
service: "ConfirmationTokenService",
|
|
3567
|
-
hasDocRef: !!docRef,
|
|
3568
|
-
hasId: !!docRef?.id,
|
|
3569
|
-
docRefId: docRef?.id
|
|
3570
|
-
});
|
|
3571
|
-
if (!docRef) {
|
|
3572
|
-
const error = new Error("Firestore addDocument returned null/undefined");
|
|
3573
|
-
logger.error("CRITICAL: addDocument returned null", {
|
|
3574
|
-
service: "ConfirmationTokenService",
|
|
3575
|
-
userId,
|
|
3576
|
-
collectionPath
|
|
3577
|
-
});
|
|
3578
|
-
throw error;
|
|
3579
|
-
}
|
|
3580
|
-
if (!docRef.id) {
|
|
3581
|
-
const error = new Error("Firestore addDocument returned docRef without ID");
|
|
3582
|
-
logger.error("CRITICAL: docRef has no ID", {
|
|
3583
|
-
service: "ConfirmationTokenService",
|
|
3584
|
-
userId,
|
|
3585
|
-
collectionPath,
|
|
3586
|
-
docRef
|
|
3587
|
-
});
|
|
3588
|
-
throw error;
|
|
3589
|
-
}
|
|
3590
|
-
logger.info("Confirmation request created successfully", {
|
|
3591
|
-
service: "ConfirmationTokenService",
|
|
3592
|
-
requestId: docRef.id,
|
|
3593
|
-
token,
|
|
3594
|
-
expiresAt: request.expires_at
|
|
3595
|
-
});
|
|
3596
|
-
return { requestId: docRef.id, token };
|
|
3597
|
-
} catch (error) {
|
|
3598
|
-
logger.error("Failed to create confirmation request", {
|
|
3599
|
-
service: "ConfirmationTokenService",
|
|
3600
|
-
error: error instanceof Error ? error.message : String(error),
|
|
3601
|
-
stack: error instanceof Error ? error.stack : void 0,
|
|
3602
|
-
userId,
|
|
3603
|
-
action,
|
|
3604
|
-
collectionPath: `users/${userId}/requests`
|
|
3605
|
-
});
|
|
3606
|
-
throw error;
|
|
3607
|
-
}
|
|
3608
|
-
}
|
|
3609
|
-
/**
|
|
3610
|
-
* Validate and retrieve a confirmation request
|
|
3611
|
-
*
|
|
3612
|
-
* @param userId - User ID
|
|
3613
|
-
* @param token - Confirmation token
|
|
3614
|
-
* @returns Request with request_id if valid, null otherwise
|
|
3615
|
-
*/
|
|
3616
|
-
async validateToken(userId, token) {
|
|
3617
|
-
const collectionPath = `users/${userId}/requests`;
|
|
3618
|
-
logger.debug("Validating confirmation token", {
|
|
3619
|
-
service: "ConfirmationTokenService",
|
|
3620
|
-
userId,
|
|
3621
|
-
token,
|
|
3622
|
-
collectionPath
|
|
3623
|
-
});
|
|
3624
|
-
const queryOptions = {
|
|
3625
|
-
where: [
|
|
3626
|
-
{ field: "token", op: "==", value: token },
|
|
3627
|
-
{ field: "status", op: "==", value: "pending" }
|
|
3628
|
-
],
|
|
3629
|
-
limit: 1
|
|
3630
|
-
};
|
|
3631
|
-
const results = await queryDocuments(collectionPath, queryOptions);
|
|
3632
|
-
logger.debug("Token query results", {
|
|
3633
|
-
service: "ConfirmationTokenService",
|
|
3634
|
-
resultsFound: results.length,
|
|
3635
|
-
hasResults: results.length > 0
|
|
3636
|
-
});
|
|
3637
|
-
if (results.length === 0) {
|
|
3638
|
-
logger.info("Token not found or not pending", {
|
|
3639
|
-
service: "ConfirmationTokenService",
|
|
3640
|
-
userId
|
|
3641
|
-
});
|
|
3642
|
-
return null;
|
|
3643
|
-
}
|
|
3644
|
-
const doc = results[0];
|
|
3645
|
-
const request = doc.data;
|
|
3646
|
-
logger.info("Confirmation request found", {
|
|
3647
|
-
service: "ConfirmationTokenService",
|
|
3648
|
-
requestId: doc.id,
|
|
3649
|
-
action: request.action,
|
|
3650
|
-
status: request.status,
|
|
3651
|
-
expiresAt: request.expires_at
|
|
3652
|
-
});
|
|
3653
|
-
const expiresAt = new Date(request.expires_at);
|
|
3654
|
-
if (expiresAt.getTime() < Date.now()) {
|
|
3655
|
-
logger.info("Token expired", {
|
|
3656
|
-
service: "ConfirmationTokenService",
|
|
3657
|
-
requestId: doc.id,
|
|
3658
|
-
expiresAt: request.expires_at
|
|
3659
|
-
});
|
|
3660
|
-
await this.updateStatus(userId, doc.id, "expired");
|
|
3661
|
-
return null;
|
|
3662
|
-
}
|
|
3663
|
-
return {
|
|
3664
|
-
...request,
|
|
3665
|
-
request_id: doc.id
|
|
3666
|
-
};
|
|
3667
|
-
}
|
|
3668
|
-
/**
|
|
3669
|
-
* Confirm a request
|
|
3670
|
-
*
|
|
3671
|
-
* @param userId - User ID
|
|
3672
|
-
* @param token - Confirmation token
|
|
3673
|
-
* @returns Confirmed request if valid, null otherwise
|
|
3674
|
-
*/
|
|
3675
|
-
async confirmRequest(userId, token) {
|
|
3676
|
-
const request = await this.validateToken(userId, token);
|
|
3677
|
-
if (!request) {
|
|
3678
|
-
return null;
|
|
3679
|
-
}
|
|
3680
|
-
await this.updateStatus(userId, request.request_id, "confirmed");
|
|
3681
|
-
return {
|
|
3682
|
-
...request,
|
|
3683
|
-
status: "confirmed",
|
|
3684
|
-
confirmed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3685
|
-
};
|
|
3686
|
-
}
|
|
3687
|
-
/**
|
|
3688
|
-
* Deny a request
|
|
3689
|
-
*
|
|
3690
|
-
* @param userId - User ID
|
|
3691
|
-
* @param token - Confirmation token
|
|
3692
|
-
* @returns True if denied successfully, false otherwise
|
|
3693
|
-
*/
|
|
3694
|
-
async denyRequest(userId, token) {
|
|
3695
|
-
const request = await this.validateToken(userId, token);
|
|
3696
|
-
if (!request) {
|
|
3697
|
-
return false;
|
|
3698
|
-
}
|
|
3699
|
-
await this.updateStatus(userId, request.request_id, "denied");
|
|
3700
|
-
return true;
|
|
3701
|
-
}
|
|
3702
|
-
/**
|
|
3703
|
-
* Retract a request
|
|
3704
|
-
*
|
|
3705
|
-
* @param userId - User ID
|
|
3706
|
-
* @param token - Confirmation token
|
|
3707
|
-
* @returns True if retracted successfully, false otherwise
|
|
3708
|
-
*/
|
|
3709
|
-
async retractRequest(userId, token) {
|
|
3710
|
-
const request = await this.validateToken(userId, token);
|
|
3711
|
-
if (!request) {
|
|
3712
|
-
return false;
|
|
3713
|
-
}
|
|
3714
|
-
await this.updateStatus(userId, request.request_id, "retracted");
|
|
3715
|
-
return true;
|
|
3716
|
-
}
|
|
3717
|
-
/**
|
|
3718
|
-
* Update request status
|
|
3719
|
-
*
|
|
3720
|
-
* @param userId - User ID
|
|
3721
|
-
* @param requestId - Request document ID
|
|
3722
|
-
* @param status - New status
|
|
3723
|
-
*/
|
|
3724
|
-
async updateStatus(userId, requestId, status) {
|
|
3725
|
-
const collectionPath = `users/${userId}/requests`;
|
|
3726
|
-
const updateData = {
|
|
3727
|
-
status
|
|
3728
|
-
};
|
|
3729
|
-
if (status === "confirmed") {
|
|
3730
|
-
updateData.confirmed_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
3731
|
-
}
|
|
3732
|
-
await updateDocument(collectionPath, requestId, updateData);
|
|
3733
|
-
}
|
|
3734
|
-
/**
|
|
3735
|
-
* Clean up expired requests (optional - Firestore TTL handles deletion)
|
|
3736
|
-
*
|
|
3737
|
-
* Note: Configure Firestore TTL policy on 'requests' collection group
|
|
3738
|
-
* with 'expires_at' field for automatic deletion within 24 hours.
|
|
3739
|
-
*
|
|
3740
|
-
* This method is optional for immediate cleanup if needed.
|
|
3741
|
-
*
|
|
3742
|
-
* @returns Count of deleted requests
|
|
3743
|
-
*/
|
|
3744
|
-
async cleanupExpired() {
|
|
3745
|
-
logger.warn("cleanupExpired not implemented - relying on Firestore TTL", {
|
|
3746
|
-
service: "ConfirmationTokenService",
|
|
3747
|
-
note: "Configure Firestore TTL policy on requests collection group"
|
|
3748
|
-
});
|
|
3749
|
-
return 0;
|
|
3750
|
-
}
|
|
3751
|
-
};
|
|
3752
|
-
var confirmationTokenService = new ConfirmationTokenService();
|
|
3753
|
-
|
|
3754
4023
|
// src/weaviate/space-schema.ts
|
|
3755
4024
|
init_space_memory();
|
|
3756
4025
|
init_logger();
|
|
@@ -3791,11 +4060,6 @@ async function createSpaceCollection(client2, spaceId) {
|
|
|
3791
4060
|
dataType: "text[]",
|
|
3792
4061
|
description: 'Spaces this memory is published to (e.g., ["the_void", "dogs"])'
|
|
3793
4062
|
},
|
|
3794
|
-
{
|
|
3795
|
-
name: "space_id",
|
|
3796
|
-
dataType: "text",
|
|
3797
|
-
description: "DEPRECATED: Use spaces array instead. Will be removed in v3.0.0."
|
|
3798
|
-
},
|
|
3799
4063
|
{
|
|
3800
4064
|
name: "author_id",
|
|
3801
4065
|
dataType: "text",
|
|
@@ -4020,6 +4284,22 @@ async function createSpaceCollection(client2, spaceId) {
|
|
|
4020
4284
|
name: "moderation_flags",
|
|
4021
4285
|
dataType: "text[]",
|
|
4022
4286
|
description: 'Per-space moderation flags (format: "{space_id}:{flag_type}")'
|
|
4287
|
+
},
|
|
4288
|
+
// Soft delete fields
|
|
4289
|
+
{
|
|
4290
|
+
name: "deleted_at",
|
|
4291
|
+
dataType: "date",
|
|
4292
|
+
description: "Timestamp when memory was soft-deleted (null = not deleted)"
|
|
4293
|
+
},
|
|
4294
|
+
{
|
|
4295
|
+
name: "deleted_by",
|
|
4296
|
+
dataType: "text",
|
|
4297
|
+
description: "User ID who deleted the memory"
|
|
4298
|
+
},
|
|
4299
|
+
{
|
|
4300
|
+
name: "deletion_reason",
|
|
4301
|
+
dataType: "text",
|
|
4302
|
+
description: "Optional reason for deletion"
|
|
4023
4303
|
}
|
|
4024
4304
|
]
|
|
4025
4305
|
});
|
|
@@ -4073,7 +4353,14 @@ var publishTool = {
|
|
|
4073
4353
|
}
|
|
4074
4354
|
};
|
|
4075
4355
|
async function handlePublish(args, userId) {
|
|
4356
|
+
const debug = createDebugLogger({
|
|
4357
|
+
tool: "remember_publish",
|
|
4358
|
+
userId,
|
|
4359
|
+
operation: "publish_request"
|
|
4360
|
+
});
|
|
4076
4361
|
try {
|
|
4362
|
+
debug.info("Tool invoked");
|
|
4363
|
+
debug.trace("Arguments", { args });
|
|
4077
4364
|
logger.info("Starting publish request", {
|
|
4078
4365
|
tool: "remember_publish",
|
|
4079
4366
|
userId,
|
|
@@ -4082,8 +4369,10 @@ async function handlePublish(args, userId) {
|
|
|
4082
4369
|
spaceCount: args.spaces.length,
|
|
4083
4370
|
additionalTags: args.additional_tags?.length || 0
|
|
4084
4371
|
});
|
|
4372
|
+
debug.debug("Validating space IDs", { spaces: args.spaces });
|
|
4085
4373
|
const invalidSpaces = args.spaces.filter((s) => !isValidSpaceId(s));
|
|
4086
4374
|
if (invalidSpaces.length > 0) {
|
|
4375
|
+
debug.warn("Invalid space IDs detected", { invalidSpaces });
|
|
4087
4376
|
logger.warn("Invalid space IDs provided", {
|
|
4088
4377
|
tool: "remember_publish",
|
|
4089
4378
|
invalidSpaces,
|
|
@@ -4127,7 +4416,9 @@ async function handlePublish(args, userId) {
|
|
|
4127
4416
|
memoryId: args.memory_id
|
|
4128
4417
|
});
|
|
4129
4418
|
const userCollection = weaviateClient.collections.get(collectionName);
|
|
4130
|
-
const memory = await
|
|
4419
|
+
const memory = await debug.time("Fetch memory from user collection", async () => {
|
|
4420
|
+
return await fetchMemoryWithAllProperties(userCollection, args.memory_id);
|
|
4421
|
+
});
|
|
4131
4422
|
logger.debug("Memory fetch result", {
|
|
4132
4423
|
tool: "remember_publish",
|
|
4133
4424
|
found: !!memory,
|
|
@@ -4222,6 +4513,10 @@ async function handlePublish(args, userId) {
|
|
|
4222
4513
|
2
|
|
4223
4514
|
);
|
|
4224
4515
|
} catch (error) {
|
|
4516
|
+
debug.error("Tool failed", {
|
|
4517
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4518
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
4519
|
+
});
|
|
4225
4520
|
return handleToolError(error, {
|
|
4226
4521
|
toolName: "remember_publish",
|
|
4227
4522
|
userId,
|
|
@@ -4259,13 +4554,23 @@ Violating these requirements bypasses user consent and is a security violation.`
|
|
|
4259
4554
|
}
|
|
4260
4555
|
};
|
|
4261
4556
|
async function handleConfirm(args, userId) {
|
|
4557
|
+
const debug = createDebugLogger({
|
|
4558
|
+
tool: "remember_confirm",
|
|
4559
|
+
userId,
|
|
4560
|
+
operation: "confirm_action"
|
|
4561
|
+
});
|
|
4262
4562
|
try {
|
|
4563
|
+
debug.info("Tool invoked");
|
|
4564
|
+
debug.trace("Arguments", { token: args.token });
|
|
4263
4565
|
logger.info("Starting confirmation", {
|
|
4264
4566
|
tool: "remember_confirm",
|
|
4265
4567
|
userId,
|
|
4266
4568
|
token: args.token
|
|
4267
4569
|
});
|
|
4268
|
-
|
|
4570
|
+
debug.debug("Validating confirmation token");
|
|
4571
|
+
const request = await debug.time("Confirm token", async () => {
|
|
4572
|
+
return await confirmationTokenService.confirmRequest(userId, args.token);
|
|
4573
|
+
});
|
|
4269
4574
|
logger.debug("Token validation result", {
|
|
4270
4575
|
tool: "remember_confirm",
|
|
4271
4576
|
requestFound: !!request,
|
|
@@ -4294,8 +4599,15 @@ async function handleConfirm(args, userId) {
|
|
|
4294
4599
|
if (request.action === "publish_memory") {
|
|
4295
4600
|
return await executePublishMemory(request, userId);
|
|
4296
4601
|
}
|
|
4602
|
+
if (request.action === "delete_memory") {
|
|
4603
|
+
return await executeDeleteMemory(request, userId);
|
|
4604
|
+
}
|
|
4297
4605
|
throw new Error(`Unknown action type: ${request.action}`);
|
|
4298
4606
|
} catch (error) {
|
|
4607
|
+
debug.error("Tool failed", {
|
|
4608
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4609
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
4610
|
+
});
|
|
4299
4611
|
handleToolError(error, {
|
|
4300
4612
|
toolName: "remember_confirm",
|
|
4301
4613
|
userId,
|
|
@@ -4305,7 +4617,16 @@ async function handleConfirm(args, userId) {
|
|
|
4305
4617
|
}
|
|
4306
4618
|
}
|
|
4307
4619
|
async function executePublishMemory(request, userId) {
|
|
4620
|
+
const debug = createDebugLogger({
|
|
4621
|
+
tool: "remember_confirm",
|
|
4622
|
+
userId,
|
|
4623
|
+
operation: "execute_publish"
|
|
4624
|
+
});
|
|
4308
4625
|
try {
|
|
4626
|
+
debug.debug("Executing publish memory action", {
|
|
4627
|
+
memoryId: request.payload.memory_id,
|
|
4628
|
+
spaces: request.payload.spaces
|
|
4629
|
+
});
|
|
4309
4630
|
logger.info("Executing publish memory action", {
|
|
4310
4631
|
function: "executePublishMemory",
|
|
4311
4632
|
userId,
|
|
@@ -4322,10 +4643,12 @@ async function executePublishMemory(request, userId) {
|
|
|
4322
4643
|
collectionName: getMemoryCollectionName(userId),
|
|
4323
4644
|
memoryId: request.payload.memory_id
|
|
4324
4645
|
});
|
|
4325
|
-
const originalMemory = await
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4646
|
+
const originalMemory = await debug.time("Fetch original memory", async () => {
|
|
4647
|
+
return await fetchMemoryWithAllProperties(
|
|
4648
|
+
userCollection,
|
|
4649
|
+
request.payload.memory_id
|
|
4650
|
+
);
|
|
4651
|
+
});
|
|
4329
4652
|
logger.info("Original memory fetch result", {
|
|
4330
4653
|
function: "executePublishMemory",
|
|
4331
4654
|
found: !!originalMemory,
|
|
@@ -4435,14 +4758,20 @@ async function executePublishMemory(request, userId) {
|
|
|
4435
4758
|
contentLength: publishedMemory.content?.length || 0,
|
|
4436
4759
|
titleValue: publishedMemory.title || "NO_TITLE"
|
|
4437
4760
|
});
|
|
4438
|
-
const result = await
|
|
4439
|
-
|
|
4761
|
+
const result = await debug.time("Insert into Memory_public", async () => {
|
|
4762
|
+
return await publicCollection.data.insert({
|
|
4763
|
+
properties: publishedMemory
|
|
4764
|
+
});
|
|
4440
4765
|
});
|
|
4441
4766
|
logger.info("Memory published successfully", {
|
|
4442
4767
|
function: "executePublishMemory",
|
|
4443
4768
|
spaceMemoryId: result,
|
|
4444
4769
|
spaces: request.payload.spaces
|
|
4445
4770
|
});
|
|
4771
|
+
debug.info("Memory published successfully", {
|
|
4772
|
+
spaceMemoryId: result,
|
|
4773
|
+
spaces: request.payload.spaces
|
|
4774
|
+
});
|
|
4446
4775
|
try {
|
|
4447
4776
|
await userCollection.data.update({
|
|
4448
4777
|
id: request.payload.memory_id,
|
|
@@ -4473,6 +4802,10 @@ async function executePublishMemory(request, userId) {
|
|
|
4473
4802
|
2
|
|
4474
4803
|
);
|
|
4475
4804
|
} catch (error) {
|
|
4805
|
+
debug.error("Execute publish failed", {
|
|
4806
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4807
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
4808
|
+
});
|
|
4476
4809
|
handleToolError(error, {
|
|
4477
4810
|
toolName: "remember_confirm",
|
|
4478
4811
|
userId,
|
|
@@ -4481,6 +4814,52 @@ async function executePublishMemory(request, userId) {
|
|
|
4481
4814
|
});
|
|
4482
4815
|
}
|
|
4483
4816
|
}
|
|
4817
|
+
async function executeDeleteMemory(request, userId) {
|
|
4818
|
+
try {
|
|
4819
|
+
logger.info("Executing delete memory action", {
|
|
4820
|
+
function: "executeDeleteMemory",
|
|
4821
|
+
userId,
|
|
4822
|
+
memoryId: request.payload.memory_id,
|
|
4823
|
+
hasReason: !!request.payload.reason
|
|
4824
|
+
});
|
|
4825
|
+
const { memory_id, reason } = request.payload;
|
|
4826
|
+
const client2 = getWeaviateClient();
|
|
4827
|
+
const collectionName = `Memory_${sanitizeUserId(userId)}`;
|
|
4828
|
+
const collection = client2.collections.get(collectionName);
|
|
4829
|
+
await collection.data.update({
|
|
4830
|
+
id: memory_id,
|
|
4831
|
+
properties: {
|
|
4832
|
+
deleted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4833
|
+
deleted_by: userId,
|
|
4834
|
+
deletion_reason: reason || null
|
|
4835
|
+
}
|
|
4836
|
+
});
|
|
4837
|
+
logger.info("Memory soft-deleted successfully", {
|
|
4838
|
+
function: "executeDeleteMemory",
|
|
4839
|
+
userId,
|
|
4840
|
+
memoryId: memory_id,
|
|
4841
|
+
deletedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4842
|
+
});
|
|
4843
|
+
return JSON.stringify(
|
|
4844
|
+
{
|
|
4845
|
+
success: true,
|
|
4846
|
+
memory_id,
|
|
4847
|
+
message: "Memory deleted successfully"
|
|
4848
|
+
},
|
|
4849
|
+
null,
|
|
4850
|
+
2
|
|
4851
|
+
);
|
|
4852
|
+
} catch (error) {
|
|
4853
|
+
logger.error("Failed to execute delete memory", {
|
|
4854
|
+
function: "executeDeleteMemory",
|
|
4855
|
+
userId,
|
|
4856
|
+
memoryId: request.payload.memory_id,
|
|
4857
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4858
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
4859
|
+
});
|
|
4860
|
+
throw error;
|
|
4861
|
+
}
|
|
4862
|
+
}
|
|
4484
4863
|
|
|
4485
4864
|
// src/tools/deny.ts
|
|
4486
4865
|
var denyTool = {
|
|
@@ -4539,7 +4918,7 @@ async function handleDeny(args, userId) {
|
|
|
4539
4918
|
}
|
|
4540
4919
|
|
|
4541
4920
|
// src/tools/search-space.ts
|
|
4542
|
-
import { Filters as
|
|
4921
|
+
import { Filters as Filters4 } from "weaviate-client";
|
|
4543
4922
|
init_space_memory();
|
|
4544
4923
|
var searchSpaceTool = {
|
|
4545
4924
|
name: "remember_search_space",
|
|
@@ -4617,7 +4996,15 @@ Let the search algorithm find ALL relevant memories regardless of type unless ex
|
|
|
4617
4996
|
}
|
|
4618
4997
|
};
|
|
4619
4998
|
async function handleSearchSpace(args, userId) {
|
|
4999
|
+
const debug = createDebugLogger({
|
|
5000
|
+
tool: "remember_search_space",
|
|
5001
|
+
userId,
|
|
5002
|
+
operation: "search_spaces"
|
|
5003
|
+
});
|
|
4620
5004
|
try {
|
|
5005
|
+
debug.info("Tool invoked");
|
|
5006
|
+
debug.trace("Arguments", { args });
|
|
5007
|
+
debug.debug("Validating space IDs", { spaces: args.spaces });
|
|
4621
5008
|
const invalidSpaces = args.spaces.filter((s) => !isValidSpaceId(s));
|
|
4622
5009
|
if (invalidSpaces.length > 0) {
|
|
4623
5010
|
return JSON.stringify(
|
|
@@ -4674,11 +5061,22 @@ async function handleSearchSpace(args, userId) {
|
|
|
4674
5061
|
if (args.date_to) {
|
|
4675
5062
|
filterList.push(publicCollection.filter.byProperty("created_at").lessOrEqual(new Date(args.date_to)));
|
|
4676
5063
|
}
|
|
4677
|
-
const whereFilter = filterList.length > 0 ?
|
|
4678
|
-
|
|
5064
|
+
const whereFilter = filterList.length > 0 ? Filters4.and(...filterList) : void 0;
|
|
5065
|
+
debug.debug("Executing hybrid search", {
|
|
5066
|
+
query: args.query,
|
|
5067
|
+
filterCount: filterList.length,
|
|
4679
5068
|
limit: args.limit || 10,
|
|
4680
|
-
offset: args.offset || 0
|
|
4681
|
-
|
|
5069
|
+
offset: args.offset || 0
|
|
5070
|
+
});
|
|
5071
|
+
const searchResults = await debug.time("Hybrid search query", async () => {
|
|
5072
|
+
return await publicCollection.query.hybrid(args.query, {
|
|
5073
|
+
limit: args.limit || 10,
|
|
5074
|
+
offset: args.offset || 0,
|
|
5075
|
+
...whereFilter && { where: whereFilter }
|
|
5076
|
+
});
|
|
5077
|
+
});
|
|
5078
|
+
debug.debug("Search completed", {
|
|
5079
|
+
resultCount: searchResults.objects.length
|
|
4682
5080
|
});
|
|
4683
5081
|
const memories = searchResults.objects.map((obj) => ({
|
|
4684
5082
|
id: obj.uuid,
|
|
@@ -4693,8 +5091,16 @@ async function handleSearchSpace(args, userId) {
|
|
|
4693
5091
|
offset: args.offset || 0,
|
|
4694
5092
|
limit: args.limit || 10
|
|
4695
5093
|
};
|
|
5094
|
+
debug.info("Tool completed successfully", {
|
|
5095
|
+
resultCount: memories.length,
|
|
5096
|
+
spaces: args.spaces
|
|
5097
|
+
});
|
|
4696
5098
|
return JSON.stringify(result, null, 2);
|
|
4697
5099
|
} catch (error) {
|
|
5100
|
+
debug.error("Tool failed", {
|
|
5101
|
+
error: error instanceof Error ? error.message : String(error),
|
|
5102
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
5103
|
+
});
|
|
4698
5104
|
return handleToolError(error, {
|
|
4699
5105
|
toolName: "remember_search_space",
|
|
4700
5106
|
operation: "search spaces",
|
|
@@ -4705,7 +5111,7 @@ async function handleSearchSpace(args, userId) {
|
|
|
4705
5111
|
}
|
|
4706
5112
|
|
|
4707
5113
|
// src/tools/query-space.ts
|
|
4708
|
-
import { Filters as
|
|
5114
|
+
import { Filters as Filters5 } from "weaviate-client";
|
|
4709
5115
|
init_space_memory();
|
|
4710
5116
|
var querySpaceTool = {
|
|
4711
5117
|
name: "remember_query_space",
|
|
@@ -4778,7 +5184,15 @@ Let the query algorithm find ALL relevant memories regardless of type unless exp
|
|
|
4778
5184
|
}
|
|
4779
5185
|
};
|
|
4780
5186
|
async function handleQuerySpace(args, userId) {
|
|
5187
|
+
const debug = createDebugLogger({
|
|
5188
|
+
tool: "remember_query_space",
|
|
5189
|
+
userId,
|
|
5190
|
+
operation: "query_spaces"
|
|
5191
|
+
});
|
|
4781
5192
|
try {
|
|
5193
|
+
debug.info("Tool invoked");
|
|
5194
|
+
debug.trace("Arguments", { args });
|
|
5195
|
+
debug.debug("Validating space IDs", { spaces: args.spaces });
|
|
4782
5196
|
const invalidSpaces = args.spaces.filter((s) => !isValidSpaceId(s));
|
|
4783
5197
|
if (invalidSpaces.length > 0) {
|
|
4784
5198
|
return JSON.stringify(
|
|
@@ -4827,10 +5241,21 @@ async function handleQuerySpace(args, userId) {
|
|
|
4827
5241
|
if (args.date_to) {
|
|
4828
5242
|
filterList.push(publicCollection.filter.byProperty("created_at").lessOrEqual(new Date(args.date_to)));
|
|
4829
5243
|
}
|
|
4830
|
-
const whereFilter = filterList.length > 0 ?
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
5244
|
+
const whereFilter = filterList.length > 0 ? Filters5.and(...filterList) : void 0;
|
|
5245
|
+
debug.debug("Executing semantic query", {
|
|
5246
|
+
question: args.question,
|
|
5247
|
+
filterCount: filterList.length,
|
|
5248
|
+
limit: args.limit || 10
|
|
5249
|
+
});
|
|
5250
|
+
const searchResults = await debug.time("Semantic query", async () => {
|
|
5251
|
+
return await publicCollection.query.nearText(args.question, {
|
|
5252
|
+
limit: args.limit || 10,
|
|
5253
|
+
...whereFilter && { where: whereFilter }
|
|
5254
|
+
});
|
|
5255
|
+
});
|
|
5256
|
+
debug.debug("Query completed", {
|
|
5257
|
+
resultCount: searchResults.objects.length,
|
|
5258
|
+
format: args.format || "detailed"
|
|
4834
5259
|
});
|
|
4835
5260
|
const format = args.format || "detailed";
|
|
4836
5261
|
if (format === "compact") {
|
|
@@ -4859,9 +5284,17 @@ async function handleQuerySpace(args, userId) {
|
|
|
4859
5284
|
memories,
|
|
4860
5285
|
total: memories.length
|
|
4861
5286
|
};
|
|
5287
|
+
debug.info("Tool completed successfully", {
|
|
5288
|
+
resultCount: memories.length,
|
|
5289
|
+
format: "detailed"
|
|
5290
|
+
});
|
|
4862
5291
|
return JSON.stringify(result, null, 2);
|
|
4863
5292
|
}
|
|
4864
5293
|
} catch (error) {
|
|
5294
|
+
debug.error("Tool failed", {
|
|
5295
|
+
error: error instanceof Error ? error.message : String(error),
|
|
5296
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
5297
|
+
});
|
|
4865
5298
|
return handleToolError(error, {
|
|
4866
5299
|
toolName: "remember_query_space",
|
|
4867
5300
|
operation: "query spaces",
|