@prmichaelsen/remember-mcp 3.0.0 → 3.13.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 +358 -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
|
@@ -1,25 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* remember_search_space tool
|
|
3
|
-
*
|
|
4
|
-
* Search shared spaces to discover memories from other users.
|
|
5
|
-
*
|
|
2
|
+
* remember_search_space tool (Memory Collection Pattern v2)
|
|
3
|
+
*
|
|
4
|
+
* Search shared spaces and/or groups to discover memories from other users.
|
|
5
|
+
* Queries Memory_spaces_public (for space searches) and Memory_groups_{groupId}
|
|
6
|
+
* (for group searches), then merges and deduplicates results.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
9
|
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
9
10
|
import { Filters } from 'weaviate-client';
|
|
10
11
|
import { getWeaviateClient } from '../weaviate/client.js';
|
|
11
|
-
import {
|
|
12
|
+
import { isValidSpaceId } from '../weaviate/space-schema.js';
|
|
12
13
|
import { SUPPORTED_SPACES } from '../types/space-memory.js';
|
|
13
14
|
import { handleToolError } from '../utils/error-handler.js';
|
|
14
|
-
import type { SearchFilters } from '../types/memory.js';
|
|
15
15
|
import { createDebugLogger } from '../utils/debug.js';
|
|
16
|
+
import { CollectionType, getCollectionName } from '../collections/dot-notation.js';
|
|
17
|
+
import { logger } from '../utils/logger.js';
|
|
18
|
+
import type { AuthContext } from '../types/auth.js';
|
|
19
|
+
import { canModerate, canModerateAny } from '../utils/auth-helpers.js';
|
|
16
20
|
|
|
17
21
|
/**
|
|
18
22
|
* Tool definition for remember_search_space
|
|
19
23
|
*/
|
|
20
24
|
export const searchSpaceTool: Tool = {
|
|
21
25
|
name: 'remember_search_space',
|
|
22
|
-
description: `Search
|
|
26
|
+
description: `Search shared spaces and/or groups to discover memories from other users.
|
|
27
|
+
|
|
28
|
+
Destinations:
|
|
29
|
+
- Spaces: Public shared areas (e.g., "the_void", "dogs") — queries Memory_spaces_public filtered by space_ids
|
|
30
|
+
- Groups: Private group collections — queries Memory_groups_{groupId} for each specified group
|
|
31
|
+
- Neither specified: Searches all public memories across Memory_spaces_public
|
|
32
|
+
|
|
33
|
+
Results from multiple sources are merged and deduplicated by composite ID, sorted by relevance.
|
|
23
34
|
|
|
24
35
|
⚠️ **CRITICAL - CONTENT TYPE FILTERING**: Do NOT add content_type filter unless the user explicitly requests filtering by type.
|
|
25
36
|
- ✅ CORRECT: User says "search The Void for hiking" → { spaces: ["the_void"], query: "hiking" }
|
|
@@ -32,7 +43,7 @@ Let the search algorithm find ALL relevant memories regardless of type unless ex
|
|
|
32
43
|
properties: {
|
|
33
44
|
query: {
|
|
34
45
|
type: 'string',
|
|
35
|
-
description: 'Search query
|
|
46
|
+
description: 'Search query',
|
|
36
47
|
},
|
|
37
48
|
spaces: {
|
|
38
49
|
type: 'array',
|
|
@@ -40,9 +51,20 @@ Let the search algorithm find ALL relevant memories regardless of type unless ex
|
|
|
40
51
|
type: 'string',
|
|
41
52
|
enum: SUPPORTED_SPACES,
|
|
42
53
|
},
|
|
43
|
-
description: 'Spaces to search (e.g., ["the_void", "dogs"]).
|
|
54
|
+
description: 'Spaces to search (e.g., ["the_void", "dogs"]). Omit to search all public spaces.',
|
|
55
|
+
minItems: 1,
|
|
56
|
+
},
|
|
57
|
+
groups: {
|
|
58
|
+
type: 'array',
|
|
59
|
+
items: { type: 'string' },
|
|
60
|
+
description: 'Group IDs to search (e.g., ["group-123"]). Searches Memory_groups_{groupId} for each.',
|
|
44
61
|
minItems: 1,
|
|
45
|
-
|
|
62
|
+
},
|
|
63
|
+
search_type: {
|
|
64
|
+
type: 'string',
|
|
65
|
+
enum: ['hybrid', 'bm25', 'semantic'],
|
|
66
|
+
description: 'Search algorithm: "hybrid" (default), "bm25" (keyword only), or "semantic" (vector only)',
|
|
67
|
+
default: 'hybrid',
|
|
46
68
|
},
|
|
47
69
|
content_type: {
|
|
48
70
|
type: 'string',
|
|
@@ -73,6 +95,12 @@ Let the search algorithm find ALL relevant memories regardless of type unless ex
|
|
|
73
95
|
type: 'string',
|
|
74
96
|
description: 'Filter memories created before this date (ISO 8601)',
|
|
75
97
|
},
|
|
98
|
+
moderation_filter: {
|
|
99
|
+
type: 'string',
|
|
100
|
+
enum: ['approved', 'pending', 'rejected', 'removed', 'all'],
|
|
101
|
+
description: 'Filter by moderation status. Default: "approved" (only shows approved/unmoderated). Non-approved filters require moderator permissions.',
|
|
102
|
+
default: 'approved',
|
|
103
|
+
},
|
|
76
104
|
include_comments: {
|
|
77
105
|
type: 'boolean',
|
|
78
106
|
description: 'Include comments in search results (default: false)',
|
|
@@ -89,30 +117,145 @@ Let the search algorithm find ALL relevant memories regardless of type unless ex
|
|
|
89
117
|
description: 'Offset for pagination',
|
|
90
118
|
},
|
|
91
119
|
},
|
|
92
|
-
required: ['query'
|
|
120
|
+
required: ['query'],
|
|
93
121
|
},
|
|
94
122
|
};
|
|
95
123
|
|
|
124
|
+
export type ModerationFilter = 'approved' | 'pending' | 'rejected' | 'removed' | 'all';
|
|
125
|
+
|
|
96
126
|
interface SearchSpaceArgs {
|
|
97
127
|
query: string;
|
|
98
|
-
spaces
|
|
128
|
+
spaces?: string[];
|
|
129
|
+
groups?: string[];
|
|
130
|
+
search_type?: 'hybrid' | 'bm25' | 'semantic';
|
|
99
131
|
content_type?: string;
|
|
100
132
|
tags?: string[];
|
|
101
133
|
min_weight?: number;
|
|
102
134
|
max_weight?: number;
|
|
103
135
|
date_from?: string;
|
|
104
136
|
date_to?: string;
|
|
137
|
+
moderation_filter?: ModerationFilter;
|
|
105
138
|
include_comments?: boolean;
|
|
106
139
|
limit?: number;
|
|
107
140
|
offset?: number;
|
|
108
141
|
}
|
|
109
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Build the moderation status filter for a Weaviate collection query.
|
|
145
|
+
*
|
|
146
|
+
* - 'approved' (default): matches approved OR null (backward compat for pre-moderation memories)
|
|
147
|
+
* - 'pending'/'rejected'/'removed': matches that specific status
|
|
148
|
+
* - 'all': no moderation filter applied
|
|
149
|
+
*/
|
|
150
|
+
export function buildModerationFilter(collection: any, moderationFilter: ModerationFilter = 'approved'): any | null {
|
|
151
|
+
if (moderationFilter === 'all') {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (moderationFilter === 'approved') {
|
|
156
|
+
// Approved OR null (backward compat: existing memories without moderation_status are approved)
|
|
157
|
+
return Filters.or(
|
|
158
|
+
collection.filter.byProperty('moderation_status').equal('approved'),
|
|
159
|
+
collection.filter.byProperty('moderation_status').isNull(true)
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Specific non-approved status
|
|
164
|
+
return collection.filter.byProperty('moderation_status').equal(moderationFilter);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Build base filters applied to all space/group collection queries.
|
|
169
|
+
* Excludes soft-deleted memories and optionally filters by content type, tags, weight, and date.
|
|
170
|
+
* Includes moderation status filter (default: approved/null only).
|
|
171
|
+
*/
|
|
172
|
+
export function buildBaseFilters(collection: any, args: SearchSpaceArgs): any[] {
|
|
173
|
+
const filterList: any[] = [];
|
|
174
|
+
|
|
175
|
+
// Exclude soft-deleted memories (requires indexNullState: true on collection)
|
|
176
|
+
filterList.push(collection.filter.byProperty('deleted_at').isNull(true));
|
|
177
|
+
|
|
178
|
+
// Only return memories (not relationships)
|
|
179
|
+
filterList.push(collection.filter.byProperty('doc_type').equal('memory'));
|
|
180
|
+
|
|
181
|
+
// Moderation status filter
|
|
182
|
+
const moderationFilter = buildModerationFilter(collection, args.moderation_filter);
|
|
183
|
+
if (moderationFilter) {
|
|
184
|
+
filterList.push(moderationFilter);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Apply content type filter
|
|
188
|
+
if (args.content_type) {
|
|
189
|
+
filterList.push(collection.filter.byProperty('content_type').equal(args.content_type));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Exclude comments and ghost memories by default (unless content_type is explicitly set)
|
|
193
|
+
if (!args.include_comments && !args.content_type) {
|
|
194
|
+
filterList.push(collection.filter.byProperty('content_type').notEqual('comment'));
|
|
195
|
+
}
|
|
196
|
+
if (!args.content_type) {
|
|
197
|
+
filterList.push(collection.filter.byProperty('content_type').notEqual('ghost'));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Apply tags filter (AND semantics: memory must have ALL specified tags)
|
|
201
|
+
if (args.tags && args.tags.length > 0) {
|
|
202
|
+
args.tags.forEach(tag => {
|
|
203
|
+
filterList.push(collection.filter.byProperty('tags').containsAny([tag]));
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Apply weight filters
|
|
208
|
+
if (args.min_weight !== undefined) {
|
|
209
|
+
filterList.push(collection.filter.byProperty('weight').greaterOrEqual(args.min_weight));
|
|
210
|
+
}
|
|
211
|
+
if (args.max_weight !== undefined) {
|
|
212
|
+
filterList.push(collection.filter.byProperty('weight').lessOrEqual(args.max_weight));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Apply date filters (created_at stored as ISO 8601 text, sorts lexicographically)
|
|
216
|
+
if (args.date_from) {
|
|
217
|
+
filterList.push(collection.filter.byProperty('created_at').greaterOrEqual(new Date(args.date_from)));
|
|
218
|
+
}
|
|
219
|
+
if (args.date_to) {
|
|
220
|
+
filterList.push(collection.filter.byProperty('created_at').lessOrEqual(new Date(args.date_to)));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return filterList;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Execute a search against a Weaviate collection using the specified search type.
|
|
228
|
+
*/
|
|
229
|
+
async function executeSearch(
|
|
230
|
+
collection: any,
|
|
231
|
+
query: string,
|
|
232
|
+
searchType: 'hybrid' | 'bm25' | 'semantic',
|
|
233
|
+
whereFilter: any,
|
|
234
|
+
limit: number
|
|
235
|
+
): Promise<any[]> {
|
|
236
|
+
const opts = {
|
|
237
|
+
limit,
|
|
238
|
+
...(whereFilter && { where: whereFilter }),
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
switch (searchType) {
|
|
242
|
+
case 'bm25':
|
|
243
|
+
return (await collection.query.bm25(query, opts)).objects;
|
|
244
|
+
case 'semantic':
|
|
245
|
+
return (await collection.query.nearText([query], opts)).objects;
|
|
246
|
+
case 'hybrid':
|
|
247
|
+
default:
|
|
248
|
+
return (await collection.query.hybrid(query, opts)).objects;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
110
252
|
/**
|
|
111
253
|
* Handle remember_search_space tool execution
|
|
112
254
|
*/
|
|
113
255
|
export async function handleSearchSpace(
|
|
114
256
|
args: SearchSpaceArgs,
|
|
115
|
-
userId: string
|
|
257
|
+
userId: string,
|
|
258
|
+
authContext?: AuthContext
|
|
116
259
|
): Promise<string> {
|
|
117
260
|
const debug = createDebugLogger({
|
|
118
261
|
tool: 'remember_search_space',
|
|
@@ -123,130 +266,210 @@ export async function handleSearchSpace(
|
|
|
123
266
|
try {
|
|
124
267
|
debug.info('Tool invoked');
|
|
125
268
|
debug.trace('Arguments', { args });
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
269
|
+
|
|
270
|
+
const spaces = args.spaces || [];
|
|
271
|
+
const groups = args.groups || [];
|
|
272
|
+
const searchType = args.search_type || 'hybrid';
|
|
273
|
+
const limit = args.limit || 10;
|
|
274
|
+
const offset = args.offset || 0;
|
|
275
|
+
|
|
276
|
+
// Validate space IDs
|
|
277
|
+
if (spaces.length > 0) {
|
|
278
|
+
const invalidSpaces = spaces.filter(s => !isValidSpaceId(s));
|
|
279
|
+
if (invalidSpaces.length > 0) {
|
|
280
|
+
return JSON.stringify(
|
|
281
|
+
{
|
|
282
|
+
success: false,
|
|
283
|
+
error: 'Invalid space IDs',
|
|
284
|
+
message: `Invalid spaces: ${invalidSpaces.join(', ')}. Supported spaces: ${SUPPORTED_SPACES.join(', ')}`,
|
|
285
|
+
context: {
|
|
286
|
+
invalid_spaces: invalidSpaces,
|
|
287
|
+
provided_spaces: spaces,
|
|
288
|
+
supported_spaces: SUPPORTED_SPACES,
|
|
289
|
+
},
|
|
140
290
|
},
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
291
|
+
null,
|
|
292
|
+
2
|
|
293
|
+
);
|
|
294
|
+
}
|
|
145
295
|
}
|
|
146
|
-
|
|
147
|
-
// Validate
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
296
|
+
|
|
297
|
+
// Validate group IDs
|
|
298
|
+
if (groups.length > 0) {
|
|
299
|
+
const invalidGroups = groups.filter(g => !g || g.includes('.') || g.trim() === '');
|
|
300
|
+
if (invalidGroups.length > 0) {
|
|
301
|
+
return JSON.stringify(
|
|
302
|
+
{
|
|
303
|
+
success: false,
|
|
304
|
+
error: 'Invalid group IDs',
|
|
305
|
+
message: 'Group IDs cannot be empty or contain dots',
|
|
306
|
+
context: { invalid_groups: invalidGroups },
|
|
307
|
+
},
|
|
308
|
+
null,
|
|
309
|
+
2
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Permission check: non-approved moderation filters require can_moderate
|
|
315
|
+
const moderationFilter = args.moderation_filter || 'approved';
|
|
316
|
+
if (moderationFilter !== 'approved') {
|
|
317
|
+
// For group searches: check can_moderate per group
|
|
318
|
+
for (const groupId of groups) {
|
|
319
|
+
if (!canModerate(authContext, groupId)) {
|
|
320
|
+
return JSON.stringify(
|
|
321
|
+
{
|
|
322
|
+
success: false,
|
|
323
|
+
error: 'Permission denied',
|
|
324
|
+
message: `Moderator access required to view ${moderationFilter} memories in group ${groupId}`,
|
|
325
|
+
},
|
|
326
|
+
null,
|
|
327
|
+
2
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
// For space searches: check can_moderate on any group
|
|
332
|
+
if ((spaces.length > 0 || groups.length === 0) && !canModerateAny(authContext)) {
|
|
333
|
+
return JSON.stringify(
|
|
334
|
+
{
|
|
335
|
+
success: false,
|
|
336
|
+
error: 'Permission denied',
|
|
337
|
+
message: `Moderator access required to view ${moderationFilter} memories in spaces`,
|
|
338
|
+
},
|
|
339
|
+
null,
|
|
340
|
+
2
|
|
341
|
+
);
|
|
342
|
+
}
|
|
158
343
|
}
|
|
159
344
|
|
|
160
345
|
const weaviateClient = getWeaviateClient();
|
|
161
|
-
|
|
346
|
+
// Fetch enough results before pagination so we can deduplicate across sources
|
|
347
|
+
const fetchLimit = (limit + offset) * Math.max(1, groups.length + (spaces.length > 0 || groups.length === 0 ? 1 : 0));
|
|
348
|
+
const allObjects: any[] = [];
|
|
162
349
|
|
|
163
|
-
|
|
164
|
-
|
|
350
|
+
logger.info('Starting space/group search', {
|
|
351
|
+
tool: 'remember_search_space',
|
|
352
|
+
userId,
|
|
353
|
+
spaces,
|
|
354
|
+
groups,
|
|
355
|
+
searchType,
|
|
356
|
+
query: args.query,
|
|
357
|
+
});
|
|
165
358
|
|
|
166
|
-
//
|
|
167
|
-
|
|
359
|
+
// --- Space collection search ---
|
|
360
|
+
// Runs when spaces are specified, OR when neither spaces nor groups are specified (all-public)
|
|
361
|
+
if (spaces.length > 0 || groups.length === 0) {
|
|
362
|
+
const spacesCollectionName = getCollectionName(CollectionType.SPACES);
|
|
363
|
+
const spacesCollection = weaviateClient.collections.get(spacesCollectionName);
|
|
168
364
|
|
|
169
|
-
|
|
170
|
-
filterList.push(publicCollection.filter.byProperty('doc_type').equal('memory'));
|
|
365
|
+
const filterList = buildBaseFilters(spacesCollection, args);
|
|
171
366
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
367
|
+
// Filter by space_ids array when specific spaces are requested
|
|
368
|
+
if (spaces.length > 0) {
|
|
369
|
+
filterList.push(spacesCollection.filter.byProperty('space_ids').containsAny(spaces));
|
|
370
|
+
}
|
|
371
|
+
// When spaces.length === 0 and groups.length === 0: no space_ids filter → all-public search
|
|
176
372
|
|
|
177
|
-
|
|
178
|
-
if (!args.include_comments && !args.content_type) {
|
|
179
|
-
// Only exclude comments if not filtering by content_type
|
|
180
|
-
// (if content_type is set, user has explicit control)
|
|
181
|
-
filterList.push(publicCollection.filter.byProperty('type').notEqual('comment'));
|
|
182
|
-
}
|
|
373
|
+
const whereFilter = filterList.length > 0 ? Filters.and(...filterList) : undefined;
|
|
183
374
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
375
|
+
debug.debug('Searching Memory_spaces_public', {
|
|
376
|
+
filterCount: filterList.length,
|
|
377
|
+
spaces,
|
|
378
|
+
allPublic: spaces.length === 0,
|
|
379
|
+
searchType,
|
|
188
380
|
});
|
|
189
|
-
}
|
|
190
381
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
382
|
+
const spaceObjects = await debug.time('Space collection search', async () => {
|
|
383
|
+
return await executeSearch(spacesCollection, args.query, searchType, whereFilter, fetchLimit);
|
|
384
|
+
});
|
|
195
385
|
|
|
196
|
-
|
|
197
|
-
filterList.push(publicCollection.filter.byProperty('weight').lessOrEqual(args.max_weight));
|
|
198
|
-
}
|
|
386
|
+
allObjects.push(...spaceObjects);
|
|
199
387
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
388
|
+
logger.info('Space collection search complete', {
|
|
389
|
+
tool: 'remember_search_space',
|
|
390
|
+
collectionName: spacesCollectionName,
|
|
391
|
+
resultCount: spaceObjects.length,
|
|
392
|
+
});
|
|
203
393
|
}
|
|
204
394
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
395
|
+
// --- Group collection searches ---
|
|
396
|
+
for (const groupId of groups) {
|
|
397
|
+
const groupCollectionName = getCollectionName(CollectionType.GROUPS, groupId);
|
|
208
398
|
|
|
209
|
-
|
|
399
|
+
// Skip if the group collection doesn't exist yet
|
|
400
|
+
const exists = await weaviateClient.collections.exists(groupCollectionName);
|
|
401
|
+
if (!exists) {
|
|
402
|
+
debug.warn('Group collection not found, skipping', { groupId, groupCollectionName });
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
210
405
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
406
|
+
const groupCollection = weaviateClient.collections.get(groupCollectionName);
|
|
407
|
+
const filterList = buildBaseFilters(groupCollection, args);
|
|
408
|
+
const whereFilter = filterList.length > 0 ? Filters.and(...filterList) : undefined;
|
|
409
|
+
|
|
410
|
+
debug.debug('Searching group collection', {
|
|
411
|
+
groupId,
|
|
412
|
+
groupCollectionName,
|
|
413
|
+
filterCount: filterList.length,
|
|
414
|
+
searchType,
|
|
415
|
+
});
|
|
217
416
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
return await publicCollection.query.hybrid(args.query, {
|
|
221
|
-
limit: args.limit || 10,
|
|
222
|
-
offset: args.offset || 0,
|
|
223
|
-
...(whereFilter && { where: whereFilter }),
|
|
417
|
+
const groupObjects = await debug.time(`Group collection search: ${groupId}`, async () => {
|
|
418
|
+
return await executeSearch(groupCollection, args.query, searchType, whereFilter, fetchLimit);
|
|
224
419
|
});
|
|
420
|
+
|
|
421
|
+
allObjects.push(...groupObjects);
|
|
422
|
+
|
|
423
|
+
logger.info('Group collection search complete', {
|
|
424
|
+
tool: 'remember_search_space',
|
|
425
|
+
groupId,
|
|
426
|
+
collectionName: groupCollectionName,
|
|
427
|
+
resultCount: groupObjects.length,
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// --- Deduplicate by UUID (composite ID) ---
|
|
432
|
+
const seen = new Set<string>();
|
|
433
|
+
const deduplicated = allObjects.filter(obj => {
|
|
434
|
+
if (seen.has(obj.uuid)) return false;
|
|
435
|
+
seen.add(obj.uuid);
|
|
436
|
+
return true;
|
|
225
437
|
});
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
438
|
+
|
|
439
|
+
// --- Sort by relevance score descending ---
|
|
440
|
+
deduplicated.sort((a, b) => {
|
|
441
|
+
const scoreA = a.metadata?.score ?? 0;
|
|
442
|
+
const scoreB = b.metadata?.score ?? 0;
|
|
443
|
+
return scoreB - scoreA;
|
|
229
444
|
});
|
|
230
445
|
|
|
446
|
+
// --- Apply pagination ---
|
|
447
|
+
const paginated = deduplicated.slice(offset, offset + limit);
|
|
448
|
+
|
|
231
449
|
// Format results
|
|
232
|
-
const memories =
|
|
450
|
+
const memories = paginated.map(obj => ({
|
|
233
451
|
id: obj.uuid,
|
|
234
452
|
...obj.properties,
|
|
235
453
|
_score: obj.metadata?.score,
|
|
236
454
|
}));
|
|
237
455
|
|
|
456
|
+
const isAllPublic = spaces.length === 0 && groups.length === 0;
|
|
457
|
+
|
|
238
458
|
const result = {
|
|
239
|
-
spaces_searched:
|
|
459
|
+
spaces_searched: isAllPublic ? 'all_public' : spaces,
|
|
460
|
+
groups_searched: groups,
|
|
240
461
|
query: args.query,
|
|
462
|
+
search_type: searchType,
|
|
241
463
|
memories,
|
|
242
464
|
total: memories.length,
|
|
243
|
-
offset
|
|
244
|
-
limit
|
|
465
|
+
offset,
|
|
466
|
+
limit,
|
|
245
467
|
};
|
|
246
468
|
|
|
247
469
|
debug.info('Tool completed successfully', {
|
|
248
470
|
resultCount: memories.length,
|
|
249
|
-
spaces
|
|
471
|
+
spaces,
|
|
472
|
+
groups,
|
|
250
473
|
});
|
|
251
474
|
|
|
252
475
|
return JSON.stringify(result, null, 2);
|
|
@@ -259,6 +482,7 @@ export async function handleSearchSpace(
|
|
|
259
482
|
toolName: 'remember_search_space',
|
|
260
483
|
operation: 'search spaces',
|
|
261
484
|
spaces: args.spaces,
|
|
485
|
+
groups: args.groups,
|
|
262
486
|
query: args.query,
|
|
263
487
|
});
|
|
264
488
|
}
|
|
@@ -6,11 +6,13 @@
|
|
|
6
6
|
import { PreferencesDatabaseService } from '../services/preferences-database.service.js';
|
|
7
7
|
import { logger } from '../utils/logger.js';
|
|
8
8
|
import { handleToolError } from '../utils/error-handler.js';
|
|
9
|
+
import { createDebugLogger } from '../utils/debug.js';
|
|
9
10
|
import {
|
|
10
11
|
UserPreferences,
|
|
11
12
|
getPreferenceDescription,
|
|
12
13
|
getPreferencesSchema,
|
|
13
14
|
} from '../types/preferences.js';
|
|
15
|
+
import type { AuthContext } from '../types/auth.js';
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Tool definition for remember_set_preference
|
|
@@ -115,9 +117,15 @@ function formatPreferenceChangeMessage(updates: Partial<UserPreferences>): strin
|
|
|
115
117
|
*/
|
|
116
118
|
export async function handleSetPreference(
|
|
117
119
|
args: SetPreferenceArgs,
|
|
118
|
-
userId: string
|
|
120
|
+
userId: string,
|
|
121
|
+
authContext?: AuthContext
|
|
119
122
|
): Promise<string> {
|
|
123
|
+
const debug = createDebugLogger({ tool: 'remember_set_preference', userId, operation: 'set preference' });
|
|
124
|
+
|
|
120
125
|
try {
|
|
126
|
+
debug.info('Tool invoked');
|
|
127
|
+
debug.trace('Arguments', { args });
|
|
128
|
+
|
|
121
129
|
const { preferences } = args;
|
|
122
130
|
|
|
123
131
|
logger.info('Setting preferences', { userId, updates: Object.keys(preferences) });
|
|
@@ -140,6 +148,7 @@ export async function handleSetPreference(
|
|
|
140
148
|
|
|
141
149
|
return JSON.stringify(result, null, 2);
|
|
142
150
|
} catch (error) {
|
|
151
|
+
debug.error('Tool failed', { error: error instanceof Error ? error.message : String(error) });
|
|
143
152
|
handleToolError(error, {
|
|
144
153
|
toolName: 'remember_set_preference',
|
|
145
154
|
operation: 'set preference',
|
|
@@ -9,6 +9,8 @@ import { fetchMemoryWithAllProperties } from '../weaviate/client.js';
|
|
|
9
9
|
import { logger } from '../utils/logger.js';
|
|
10
10
|
import { handleToolError, withErrorHandling } from '../utils/error-handler.js';
|
|
11
11
|
import { isValidContentType } from '../constants/content-types.js';
|
|
12
|
+
import { createDebugLogger } from '../utils/debug.js';
|
|
13
|
+
import type { AuthContext } from '../types/auth.js';
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* Tool definition for remember_update_memory
|
|
@@ -124,9 +126,13 @@ export interface UpdateMemoryResult {
|
|
|
124
126
|
*/
|
|
125
127
|
export async function handleUpdateMemory(
|
|
126
128
|
args: UpdateMemoryArgs,
|
|
127
|
-
userId: string
|
|
129
|
+
userId: string,
|
|
130
|
+
authContext?: AuthContext
|
|
128
131
|
): Promise<string> {
|
|
132
|
+
const debug = createDebugLogger({ tool: 'remember_update_memory', userId, operation: 'update memory' });
|
|
129
133
|
try {
|
|
134
|
+
debug.info('Tool invoked');
|
|
135
|
+
debug.trace('Arguments', { args });
|
|
130
136
|
logger.info('Updating memory', { userId, memoryId: args.memory_id });
|
|
131
137
|
|
|
132
138
|
const collection = getMemoryCollection(userId);
|
|
@@ -191,8 +197,8 @@ export async function handleUpdateMemory(
|
|
|
191
197
|
if (!isValidContentType(args.type)) {
|
|
192
198
|
throw new Error(`Invalid content type: ${args.type}`);
|
|
193
199
|
}
|
|
194
|
-
updates.
|
|
195
|
-
updatedFields.push('
|
|
200
|
+
updates.content_type = args.type;
|
|
201
|
+
updatedFields.push('content_type');
|
|
196
202
|
}
|
|
197
203
|
|
|
198
204
|
// Update scoring fields
|
|
@@ -210,8 +216,8 @@ export async function handleUpdateMemory(
|
|
|
210
216
|
if (args.trust < 0 || args.trust > 1) {
|
|
211
217
|
throw new Error('Trust must be between 0 and 1');
|
|
212
218
|
}
|
|
213
|
-
updates.
|
|
214
|
-
updatedFields.push('
|
|
219
|
+
updates.trust_score = args.trust;
|
|
220
|
+
updatedFields.push('trust_score');
|
|
215
221
|
}
|
|
216
222
|
|
|
217
223
|
// Update organization fields
|
|
@@ -231,6 +237,10 @@ export async function handleUpdateMemory(
|
|
|
231
237
|
updatedFields.push('structured_content');
|
|
232
238
|
}
|
|
233
239
|
|
|
240
|
+
// NOTE: space_ids and group_ids (publication tracking arrays) are intentionally
|
|
241
|
+
// NOT exposed in UpdateMemoryArgs — they are managed exclusively by
|
|
242
|
+
// remember_publish and remember_retract. The spread below preserves them.
|
|
243
|
+
|
|
234
244
|
// Update comment/threading fields
|
|
235
245
|
if (args.parent_id !== undefined) {
|
|
236
246
|
updates.parent_id = args.parent_id;
|
|
@@ -314,6 +324,7 @@ export async function handleUpdateMemory(
|
|
|
314
324
|
|
|
315
325
|
return JSON.stringify(result, null, 2);
|
|
316
326
|
} catch (error) {
|
|
327
|
+
debug.error('Tool failed', { error: error instanceof Error ? error.message : String(error) });
|
|
317
328
|
handleToolError(error, {
|
|
318
329
|
toolName: 'remember_update_memory',
|
|
319
330
|
operation: 'update memory',
|