@prmichaelsen/remember-mcp 0.1.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 +65 -0
- package/AGENT.md +840 -0
- package/README.md +72 -0
- package/agent/design/.gitkeep +0 -0
- package/agent/design/access-control-result-pattern.md +458 -0
- package/agent/design/action-audit-memory-types.md +637 -0
- package/agent/design/common-template-fields.md +282 -0
- package/agent/design/complete-tool-set.md +407 -0
- package/agent/design/content-types-expansion.md +521 -0
- package/agent/design/cross-database-id-strategy.md +358 -0
- package/agent/design/default-template-library.md +423 -0
- package/agent/design/firestore-wrapper-analysis.md +606 -0
- package/agent/design/llm-provider-abstraction.md +691 -0
- package/agent/design/location-handling-architecture.md +523 -0
- package/agent/design/memory-templates-design.md +364 -0
- package/agent/design/permissions-storage-architecture.md +680 -0
- package/agent/design/relationship-storage-strategy.md +361 -0
- package/agent/design/remember-mcp-implementation-tasks.md +417 -0
- package/agent/design/remember-mcp-progress.yaml +141 -0
- package/agent/design/requirements-enhancements.md +468 -0
- package/agent/design/requirements.md +56 -0
- package/agent/design/template-storage-strategy.md +412 -0
- package/agent/design/template-suggestion-system.md +853 -0
- package/agent/design/trust-escalation-prevention.md +343 -0
- package/agent/design/trust-system-implementation.md +592 -0
- package/agent/design/user-preferences.md +683 -0
- package/agent/design/weaviate-collection-strategy.md +461 -0
- package/agent/milestones/.gitkeep +0 -0
- package/agent/milestones/milestone-1-project-foundation.md +121 -0
- package/agent/milestones/milestone-2-core-memory-system.md +150 -0
- package/agent/milestones/milestone-3-relationships-graph.md +116 -0
- package/agent/milestones/milestone-4-user-preferences.md +103 -0
- package/agent/milestones/milestone-5-template-system.md +126 -0
- package/agent/milestones/milestone-6-auth-multi-tenancy.md +124 -0
- package/agent/milestones/milestone-7-trust-permissions.md +133 -0
- package/agent/milestones/milestone-8-testing-quality.md +137 -0
- package/agent/milestones/milestone-9-deployment-documentation.md +147 -0
- package/agent/patterns/.gitkeep +0 -0
- package/agent/patterns/bootstrap.md +1271 -0
- package/agent/patterns/firebase-admin-sdk-v8-usage.md +950 -0
- package/agent/patterns/firestore-users-pattern-best-practices.md +347 -0
- package/agent/patterns/library-services.md +454 -0
- package/agent/patterns/testing-colocated.md +316 -0
- package/agent/progress.yaml +395 -0
- package/agent/tasks/.gitkeep +0 -0
- package/agent/tasks/task-1-initialize-project-structure.md +266 -0
- package/agent/tasks/task-2-install-dependencies.md +199 -0
- package/agent/tasks/task-3-setup-weaviate-client.md +330 -0
- package/agent/tasks/task-4-setup-firestore-client.md +362 -0
- package/agent/tasks/task-5-create-basic-mcp-server.md +114 -0
- package/agent/tasks/task-6-create-integration-tests.md +195 -0
- package/agent/tasks/task-7-finalize-milestone-1.md +363 -0
- package/agent/tasks/task-8-setup-utility-scripts.md +382 -0
- package/agent/tasks/task-9-create-server-factory.md +404 -0
- package/dist/config.d.ts +26 -0
- package/dist/constants/content-types.d.ts +60 -0
- package/dist/firestore/init.d.ts +14 -0
- package/dist/firestore/paths.d.ts +53 -0
- package/dist/firestore/paths.spec.d.ts +2 -0
- package/dist/server-factory.d.ts +40 -0
- package/dist/server-factory.js +1741 -0
- package/dist/server-factory.spec.d.ts +2 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +1690 -0
- package/dist/tools/create-memory.d.ts +94 -0
- package/dist/tools/delete-memory.d.ts +47 -0
- package/dist/tools/search-memory.d.ts +88 -0
- package/dist/types/memory.d.ts +183 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/weaviate/client.d.ts +39 -0
- package/dist/weaviate/client.spec.d.ts +2 -0
- package/dist/weaviate/schema.d.ts +29 -0
- package/esbuild.build.js +60 -0
- package/esbuild.watch.js +25 -0
- package/jest.config.js +31 -0
- package/jest.e2e.config.js +17 -0
- package/package.json +68 -0
- package/src/.gitkeep +0 -0
- package/src/config.ts +56 -0
- package/src/constants/content-types.ts +454 -0
- package/src/firestore/init.ts +68 -0
- package/src/firestore/paths.spec.ts +75 -0
- package/src/firestore/paths.ts +124 -0
- package/src/server-factory.spec.ts +60 -0
- package/src/server-factory.ts +215 -0
- package/src/server.ts +243 -0
- package/src/tools/create-memory.ts +198 -0
- package/src/tools/delete-memory.ts +126 -0
- package/src/tools/search-memory.ts +216 -0
- package/src/types/memory.ts +276 -0
- package/src/utils/logger.ts +42 -0
- package/src/weaviate/client.spec.ts +58 -0
- package/src/weaviate/client.ts +114 -0
- package/src/weaviate/schema.ts +288 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* remember_create_memory tool
|
|
3
|
+
* Creates a new memory in the user's collection
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Memory, ContentType, Location, MemoryContext } from '../types/memory.js';
|
|
7
|
+
import { ensureMemoryCollection, getMemoryCollection } from '../weaviate/schema.js';
|
|
8
|
+
import { logger } from '../utils/logger.js';
|
|
9
|
+
import { DEFAULT_CONTENT_TYPE, getContentTypeDescription, isValidContentType } from '../constants/content-types.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Tool definition for remember_create_memory
|
|
13
|
+
*/
|
|
14
|
+
export const createMemoryTool = {
|
|
15
|
+
name: 'remember_create_memory',
|
|
16
|
+
description: `Create a new memory with optional template.
|
|
17
|
+
|
|
18
|
+
Memories can store any type of information: notes, events, people, recipes, etc.
|
|
19
|
+
Each memory has a weight (significance 0-1) and trust level (access control 0-1).
|
|
20
|
+
Location and context are automatically captured from the request.
|
|
21
|
+
|
|
22
|
+
Examples:
|
|
23
|
+
- "Remember that I met Sarah at the conference"
|
|
24
|
+
- "Save this recipe for chocolate chip cookies"
|
|
25
|
+
- "Note that my tent is stored in garage bin A4"
|
|
26
|
+
`,
|
|
27
|
+
inputSchema: {
|
|
28
|
+
type: 'object',
|
|
29
|
+
properties: {
|
|
30
|
+
content: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
description: 'Memory content (main text)',
|
|
33
|
+
},
|
|
34
|
+
title: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
description: 'Optional short title',
|
|
37
|
+
},
|
|
38
|
+
type: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
description: getContentTypeDescription(),
|
|
41
|
+
default: DEFAULT_CONTENT_TYPE,
|
|
42
|
+
},
|
|
43
|
+
weight: {
|
|
44
|
+
type: 'number',
|
|
45
|
+
description: 'Significance/priority (0-1, default: 0.5)',
|
|
46
|
+
minimum: 0,
|
|
47
|
+
maximum: 1,
|
|
48
|
+
},
|
|
49
|
+
trust: {
|
|
50
|
+
type: 'number',
|
|
51
|
+
description: 'Access control level (0-1, default: 0.5)',
|
|
52
|
+
minimum: 0,
|
|
53
|
+
maximum: 1,
|
|
54
|
+
},
|
|
55
|
+
tags: {
|
|
56
|
+
type: 'array',
|
|
57
|
+
items: { type: 'string' },
|
|
58
|
+
description: 'Tags for organization',
|
|
59
|
+
},
|
|
60
|
+
references: {
|
|
61
|
+
type: 'array',
|
|
62
|
+
items: { type: 'string' },
|
|
63
|
+
description: 'Source URLs',
|
|
64
|
+
},
|
|
65
|
+
template_id: {
|
|
66
|
+
type: 'string',
|
|
67
|
+
description: 'Template ID to use (optional)',
|
|
68
|
+
},
|
|
69
|
+
skip_template_suggestion: {
|
|
70
|
+
type: 'boolean',
|
|
71
|
+
description: 'Skip automatic template suggestion',
|
|
72
|
+
default: false,
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
required: ['content'],
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Create memory arguments
|
|
81
|
+
*/
|
|
82
|
+
export interface CreateMemoryArgs {
|
|
83
|
+
content: string;
|
|
84
|
+
title?: string;
|
|
85
|
+
type?: ContentType;
|
|
86
|
+
weight?: number;
|
|
87
|
+
trust?: number;
|
|
88
|
+
tags?: string[];
|
|
89
|
+
references?: string[];
|
|
90
|
+
template_id?: string;
|
|
91
|
+
skip_template_suggestion?: boolean;
|
|
92
|
+
structured_content?: Record<string, any>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Create memory result
|
|
97
|
+
*/
|
|
98
|
+
export interface CreateMemoryResult {
|
|
99
|
+
memory_id: string;
|
|
100
|
+
created_at: string;
|
|
101
|
+
message: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Handle remember_create_memory tool
|
|
106
|
+
*/
|
|
107
|
+
export async function handleCreateMemory(
|
|
108
|
+
args: CreateMemoryArgs,
|
|
109
|
+
userId: string,
|
|
110
|
+
context?: Partial<MemoryContext>
|
|
111
|
+
): Promise<string> {
|
|
112
|
+
try {
|
|
113
|
+
logger.info('Creating memory', { userId, type: args.type });
|
|
114
|
+
|
|
115
|
+
// Ensure collection exists
|
|
116
|
+
await ensureMemoryCollection(userId);
|
|
117
|
+
const collection = getMemoryCollection(userId);
|
|
118
|
+
|
|
119
|
+
// Build memory object
|
|
120
|
+
const now = new Date().toISOString();
|
|
121
|
+
const memory: Omit<Memory, 'id'> = {
|
|
122
|
+
// Core identity
|
|
123
|
+
user_id: userId,
|
|
124
|
+
doc_type: 'memory',
|
|
125
|
+
|
|
126
|
+
// Content
|
|
127
|
+
content: args.content,
|
|
128
|
+
title: args.title,
|
|
129
|
+
summary: args.title, // Use title as summary for now
|
|
130
|
+
type: (args.type && isValidContentType(args.type) ? args.type : DEFAULT_CONTENT_TYPE) as ContentType,
|
|
131
|
+
|
|
132
|
+
// Scoring
|
|
133
|
+
weight: args.weight ?? 0.5,
|
|
134
|
+
trust: args.trust ?? 0.5,
|
|
135
|
+
confidence: 1.0,
|
|
136
|
+
|
|
137
|
+
// Location (from context or default)
|
|
138
|
+
location: {
|
|
139
|
+
gps: null,
|
|
140
|
+
address: null,
|
|
141
|
+
source: 'unavailable',
|
|
142
|
+
confidence: 0,
|
|
143
|
+
is_approximate: true,
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
// Context
|
|
147
|
+
context: {
|
|
148
|
+
timestamp: now,
|
|
149
|
+
source: {
|
|
150
|
+
type: 'api',
|
|
151
|
+
platform: 'mcp',
|
|
152
|
+
},
|
|
153
|
+
summary: context?.summary || 'Memory created via MCP',
|
|
154
|
+
conversation_id: context?.conversation_id,
|
|
155
|
+
...context,
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
// Relationships
|
|
159
|
+
relationships: [],
|
|
160
|
+
|
|
161
|
+
// Access tracking
|
|
162
|
+
access_count: 0,
|
|
163
|
+
last_accessed_at: now,
|
|
164
|
+
access_frequency: 0,
|
|
165
|
+
|
|
166
|
+
// Metadata
|
|
167
|
+
created_at: now,
|
|
168
|
+
updated_at: now,
|
|
169
|
+
version: 1,
|
|
170
|
+
tags: args.tags || [],
|
|
171
|
+
references: args.references || [],
|
|
172
|
+
|
|
173
|
+
// Template
|
|
174
|
+
template_id: args.template_id,
|
|
175
|
+
structured_content: args.structured_content,
|
|
176
|
+
|
|
177
|
+
// Computed weight
|
|
178
|
+
base_weight: args.weight ?? 0.5,
|
|
179
|
+
computed_weight: args.weight ?? 0.5,
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// Insert into Weaviate
|
|
183
|
+
const result = await collection.data.insert(memory as any);
|
|
184
|
+
|
|
185
|
+
logger.info('Memory created successfully', { memoryId: result, userId });
|
|
186
|
+
|
|
187
|
+
const response: CreateMemoryResult = {
|
|
188
|
+
memory_id: result,
|
|
189
|
+
created_at: now,
|
|
190
|
+
message: `Memory created successfully with ID: ${result}`,
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
return JSON.stringify(response, null, 2);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
logger.error('Failed to create memory:', error);
|
|
196
|
+
throw new Error(`Failed to create memory: ${error instanceof Error ? error.message : String(error)}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* remember_delete_memory tool
|
|
3
|
+
* Delete a memory from the user's collection
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { getMemoryCollection } from '../weaviate/schema.js';
|
|
7
|
+
import { logger } from '../utils/logger.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Tool definition for remember_delete_memory
|
|
11
|
+
*/
|
|
12
|
+
export const deleteMemoryTool = {
|
|
13
|
+
name: 'remember_delete_memory',
|
|
14
|
+
description: `Delete a memory from your collection.
|
|
15
|
+
|
|
16
|
+
Optionally delete connected relationships as well.
|
|
17
|
+
This action cannot be undone.
|
|
18
|
+
|
|
19
|
+
Examples:
|
|
20
|
+
- "Delete that old camping note"
|
|
21
|
+
- "Remove the recipe I saved yesterday"
|
|
22
|
+
`,
|
|
23
|
+
inputSchema: {
|
|
24
|
+
type: 'object',
|
|
25
|
+
properties: {
|
|
26
|
+
memory_id: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
description: 'ID of the memory to delete',
|
|
29
|
+
},
|
|
30
|
+
delete_relationships: {
|
|
31
|
+
type: 'boolean',
|
|
32
|
+
description: 'Also delete connected relationships. Default: false',
|
|
33
|
+
default: false,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
required: ['memory_id'],
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Delete memory arguments
|
|
42
|
+
*/
|
|
43
|
+
export interface DeleteMemoryArgs {
|
|
44
|
+
memory_id: string;
|
|
45
|
+
delete_relationships?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Delete memory result
|
|
50
|
+
*/
|
|
51
|
+
export interface DeleteMemoryResult {
|
|
52
|
+
memory_id: string;
|
|
53
|
+
deleted: boolean;
|
|
54
|
+
relationships_deleted?: number;
|
|
55
|
+
message: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Handle remember_delete_memory tool
|
|
60
|
+
*/
|
|
61
|
+
export async function handleDeleteMemory(
|
|
62
|
+
args: DeleteMemoryArgs,
|
|
63
|
+
userId: string
|
|
64
|
+
): Promise<string> {
|
|
65
|
+
try {
|
|
66
|
+
logger.info('Deleting memory', { userId, memoryId: args.memory_id });
|
|
67
|
+
|
|
68
|
+
const collection = getMemoryCollection(userId);
|
|
69
|
+
|
|
70
|
+
// Get memory to verify ownership and get relationships
|
|
71
|
+
const memory = await collection.query.fetchObjectById(args.memory_id, {
|
|
72
|
+
returnProperties: ['user_id', 'doc_type', 'relationships'],
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (!memory) {
|
|
76
|
+
throw new Error(`Memory not found: ${args.memory_id}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Verify ownership
|
|
80
|
+
if (memory.properties.user_id !== userId) {
|
|
81
|
+
throw new Error('Unauthorized: Cannot delete another user\'s memory');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Verify it's a memory (not a relationship)
|
|
85
|
+
if (memory.properties.doc_type !== 'memory') {
|
|
86
|
+
throw new Error('Cannot delete relationships using this tool. Use remember_delete_relationship instead.');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let relationshipsDeleted = 0;
|
|
90
|
+
|
|
91
|
+
// Delete connected relationships if requested
|
|
92
|
+
if (args.delete_relationships && memory.properties.relationships) {
|
|
93
|
+
const relationshipIds = memory.properties.relationships as string[];
|
|
94
|
+
|
|
95
|
+
for (const relId of relationshipIds) {
|
|
96
|
+
try {
|
|
97
|
+
await collection.data.deleteById(relId);
|
|
98
|
+
relationshipsDeleted++;
|
|
99
|
+
} catch (error) {
|
|
100
|
+
logger.warn(`Failed to delete relationship ${relId}:`, error);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Delete the memory
|
|
106
|
+
await collection.data.deleteById(args.memory_id);
|
|
107
|
+
|
|
108
|
+
logger.info('Memory deleted successfully', {
|
|
109
|
+
userId,
|
|
110
|
+
memoryId: args.memory_id,
|
|
111
|
+
relationshipsDeleted
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const result: DeleteMemoryResult = {
|
|
115
|
+
memory_id: args.memory_id,
|
|
116
|
+
deleted: true,
|
|
117
|
+
relationships_deleted: relationshipsDeleted,
|
|
118
|
+
message: `Memory deleted successfully${relationshipsDeleted > 0 ? ` (${relationshipsDeleted} relationships also deleted)` : ''}`,
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
return JSON.stringify(result, null, 2);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
logger.error('Failed to delete memory:', error);
|
|
124
|
+
throw new Error(`Failed to delete memory: ${error instanceof Error ? error.message : String(error)}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* remember_search_memory tool
|
|
3
|
+
* Search memories using hybrid semantic + keyword search
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Memory, SearchOptions, SearchResult, SearchFilters } from '../types/memory.js';
|
|
7
|
+
import { getMemoryCollection } from '../weaviate/schema.js';
|
|
8
|
+
import { logger } from '../utils/logger.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Tool definition for remember_search_memory
|
|
12
|
+
*/
|
|
13
|
+
export const searchMemoryTool = {
|
|
14
|
+
name: 'remember_search_memory',
|
|
15
|
+
description: `Search memories using hybrid semantic and keyword search.
|
|
16
|
+
|
|
17
|
+
Supports:
|
|
18
|
+
- Semantic search (meaning-based)
|
|
19
|
+
- Keyword search (exact matches)
|
|
20
|
+
- Hybrid search (balanced with alpha parameter)
|
|
21
|
+
- Filtering by type, tags, weight, trust, date range
|
|
22
|
+
- Location-based search
|
|
23
|
+
|
|
24
|
+
Examples:
|
|
25
|
+
- "Find memories about camping trips"
|
|
26
|
+
- "Search for recipes I saved"
|
|
27
|
+
- "Show me notes from last week"
|
|
28
|
+
`,
|
|
29
|
+
inputSchema: {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
query: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
description: 'Search query',
|
|
35
|
+
},
|
|
36
|
+
alpha: {
|
|
37
|
+
type: 'number',
|
|
38
|
+
description: 'Balance between semantic (1.0) and keyword (0.0) search. Default: 0.7',
|
|
39
|
+
minimum: 0,
|
|
40
|
+
maximum: 1,
|
|
41
|
+
default: 0.7,
|
|
42
|
+
},
|
|
43
|
+
limit: {
|
|
44
|
+
type: 'number',
|
|
45
|
+
description: 'Maximum number of results. Default: 10',
|
|
46
|
+
minimum: 1,
|
|
47
|
+
maximum: 100,
|
|
48
|
+
default: 10,
|
|
49
|
+
},
|
|
50
|
+
offset: {
|
|
51
|
+
type: 'number',
|
|
52
|
+
description: 'Pagination offset. Default: 0',
|
|
53
|
+
minimum: 0,
|
|
54
|
+
default: 0,
|
|
55
|
+
},
|
|
56
|
+
filters: {
|
|
57
|
+
type: 'object',
|
|
58
|
+
description: 'Optional filters',
|
|
59
|
+
properties: {
|
|
60
|
+
types: {
|
|
61
|
+
type: 'array',
|
|
62
|
+
items: { type: 'string' },
|
|
63
|
+
description: 'Filter by content types',
|
|
64
|
+
},
|
|
65
|
+
tags: {
|
|
66
|
+
type: 'array',
|
|
67
|
+
items: { type: 'string' },
|
|
68
|
+
description: 'Filter by tags',
|
|
69
|
+
},
|
|
70
|
+
weight_min: {
|
|
71
|
+
type: 'number',
|
|
72
|
+
description: 'Minimum weight (0-1)',
|
|
73
|
+
},
|
|
74
|
+
trust_min: {
|
|
75
|
+
type: 'number',
|
|
76
|
+
description: 'Minimum trust level (0-1)',
|
|
77
|
+
},
|
|
78
|
+
date_from: {
|
|
79
|
+
type: 'string',
|
|
80
|
+
description: 'Start date (ISO 8601)',
|
|
81
|
+
},
|
|
82
|
+
date_to: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: 'End date (ISO 8601)',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
include_relationships: {
|
|
89
|
+
type: 'boolean',
|
|
90
|
+
description: 'Include relationships in results. Default: false',
|
|
91
|
+
default: false,
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
required: ['query'],
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Handle remember_search_memory tool
|
|
100
|
+
*/
|
|
101
|
+
export async function handleSearchMemory(
|
|
102
|
+
args: SearchOptions,
|
|
103
|
+
userId: string
|
|
104
|
+
): Promise<string> {
|
|
105
|
+
try {
|
|
106
|
+
logger.info('Searching memories', { userId, query: args.query });
|
|
107
|
+
|
|
108
|
+
const collection = getMemoryCollection(userId);
|
|
109
|
+
const alpha = args.alpha ?? 0.7;
|
|
110
|
+
const limit = args.limit ?? 10;
|
|
111
|
+
const offset = args.offset ?? 0;
|
|
112
|
+
|
|
113
|
+
// Build where filter
|
|
114
|
+
const whereFilters: any[] = [
|
|
115
|
+
{
|
|
116
|
+
path: 'doc_type',
|
|
117
|
+
operator: 'Equal',
|
|
118
|
+
valueText: 'memory',
|
|
119
|
+
},
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
// Add type filter
|
|
123
|
+
if (args.filters?.types && args.filters.types.length > 0) {
|
|
124
|
+
whereFilters.push({
|
|
125
|
+
path: 'type',
|
|
126
|
+
operator: 'ContainsAny',
|
|
127
|
+
valueTextArray: args.filters.types,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Add weight filter
|
|
132
|
+
if (args.filters?.weight_min !== undefined) {
|
|
133
|
+
whereFilters.push({
|
|
134
|
+
path: 'weight',
|
|
135
|
+
operator: 'GreaterThanEqual',
|
|
136
|
+
valueNumber: args.filters.weight_min,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Add trust filter
|
|
141
|
+
if (args.filters?.trust_min !== undefined) {
|
|
142
|
+
whereFilters.push({
|
|
143
|
+
path: 'trust',
|
|
144
|
+
operator: 'GreaterThanEqual',
|
|
145
|
+
valueNumber: args.filters.trust_min,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Add date range filters
|
|
150
|
+
if (args.filters?.date_from) {
|
|
151
|
+
whereFilters.push({
|
|
152
|
+
path: 'created_at',
|
|
153
|
+
operator: 'GreaterThanEqual',
|
|
154
|
+
valueDate: new Date(args.filters.date_from),
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (args.filters?.date_to) {
|
|
159
|
+
whereFilters.push({
|
|
160
|
+
path: 'created_at',
|
|
161
|
+
operator: 'LessThanEqual',
|
|
162
|
+
valueDate: new Date(args.filters.date_to),
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Build search options
|
|
167
|
+
const searchOptions: any = {
|
|
168
|
+
alpha: alpha,
|
|
169
|
+
limit: limit + offset, // Get extra for offset
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// Add filters if present
|
|
173
|
+
if (whereFilters.length > 0) {
|
|
174
|
+
searchOptions.filters = whereFilters.length > 1 ? {
|
|
175
|
+
operator: 'And' as const,
|
|
176
|
+
operands: whereFilters,
|
|
177
|
+
} : whereFilters[0];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Perform hybrid search with Weaviate v3 API
|
|
181
|
+
const results = await collection.query.hybrid(args.query, searchOptions);
|
|
182
|
+
|
|
183
|
+
// Apply offset
|
|
184
|
+
const paginatedResults = results.objects.slice(offset);
|
|
185
|
+
|
|
186
|
+
// Format memories
|
|
187
|
+
const memories: Partial<Memory>[] = paginatedResults.map((obj: any) => ({
|
|
188
|
+
id: obj.uuid,
|
|
189
|
+
...obj.properties,
|
|
190
|
+
}));
|
|
191
|
+
|
|
192
|
+
// Build result
|
|
193
|
+
const searchResult: SearchResult = {
|
|
194
|
+
memories: memories as Memory[],
|
|
195
|
+
total: memories.length,
|
|
196
|
+
offset: offset,
|
|
197
|
+
limit: limit,
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// TODO: Include relationships if requested
|
|
201
|
+
if (args.include_relationships) {
|
|
202
|
+
searchResult.relationships = [];
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
logger.info('Search completed', {
|
|
206
|
+
userId,
|
|
207
|
+
query: args.query,
|
|
208
|
+
results: memories.length
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
return JSON.stringify(searchResult, null, 2);
|
|
212
|
+
} catch (error) {
|
|
213
|
+
logger.error('Failed to search memories:', error);
|
|
214
|
+
throw new Error(`Failed to search memories: ${error instanceof Error ? error.message : String(error)}`);
|
|
215
|
+
}
|
|
216
|
+
}
|