@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,361 @@
|
|
|
1
|
+
# Relationship Storage Strategy
|
|
2
|
+
|
|
3
|
+
**Concept**: Store relationships in Memory collection vs separate collection
|
|
4
|
+
**Created**: 2026-02-11
|
|
5
|
+
**Status**: Design Analysis
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The Question
|
|
10
|
+
|
|
11
|
+
Should relationships be stored:
|
|
12
|
+
- **Option A**: Separate `Relationship_{user_id}` collection
|
|
13
|
+
- **Option B**: In `Memory_{user_id}` collection with `doc_type: "relationship"`
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Analysis
|
|
18
|
+
|
|
19
|
+
### Option A: Separate Collection
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
Weaviate:
|
|
23
|
+
├── Memory_{user_id}
|
|
24
|
+
│ └── doc_type: "memory"
|
|
25
|
+
└── Relationship_{user_id}
|
|
26
|
+
└── doc_type: "relationship"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Pros**:
|
|
30
|
+
- ✅ Clear separation
|
|
31
|
+
- ✅ Different schemas
|
|
32
|
+
- ✅ Optimized indexes per type
|
|
33
|
+
|
|
34
|
+
**Cons**:
|
|
35
|
+
- ❌ Can't query memories and relationships together
|
|
36
|
+
- ❌ Need two queries to get memory with relationships
|
|
37
|
+
- ❌ More collections to manage
|
|
38
|
+
- ❌ Harder to find "memories related to X"
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
### Option B: Same Collection (RECOMMENDED)
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
Weaviate:
|
|
46
|
+
└── Memory_{user_id}
|
|
47
|
+
├── doc_type: "memory"
|
|
48
|
+
└── doc_type: "relationship"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Pros**:
|
|
52
|
+
- ✅ **Unified queries**: Search memories and relationships together
|
|
53
|
+
- ✅ **Single query**: Get memory with its relationships
|
|
54
|
+
- ✅ **Better UX**: "Show me memories about camping and their connections"
|
|
55
|
+
- ✅ **Fewer collections**: Simpler management
|
|
56
|
+
- ✅ **Relationship search**: Find relationships by observation text
|
|
57
|
+
|
|
58
|
+
**Cons**:
|
|
59
|
+
- ❌ Mixed document types in one collection
|
|
60
|
+
- ❌ Need `doc_type` filter on queries
|
|
61
|
+
|
|
62
|
+
**Verdict**: Pros outweigh cons significantly
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Recommended Approach
|
|
67
|
+
|
|
68
|
+
### Store Relationships as Special Memories
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
Memory_{user_id} Collection:
|
|
72
|
+
|
|
73
|
+
# Regular memory
|
|
74
|
+
- id: "mem_abc123"
|
|
75
|
+
doc_type: "memory"
|
|
76
|
+
user_id: "user_123"
|
|
77
|
+
content: "Amazing camping trip to Yosemite..."
|
|
78
|
+
type: "event"
|
|
79
|
+
weight: 0.8
|
|
80
|
+
trust: 0.5
|
|
81
|
+
relationships: ["rel_xyz789"] # IDs of relationships
|
|
82
|
+
|
|
83
|
+
# Relationship (stored as special memory)
|
|
84
|
+
- id: "rel_xyz789"
|
|
85
|
+
doc_type: "relationship"
|
|
86
|
+
user_id: "user_123"
|
|
87
|
+
memory_ids: ["mem_abc123", "mem_def456"]
|
|
88
|
+
relationship_type: "inspired_by"
|
|
89
|
+
observation: "Yosemite trip inspired planning for Sequoia trip"
|
|
90
|
+
strength: 0.9
|
|
91
|
+
confidence: 0.8
|
|
92
|
+
context:
|
|
93
|
+
conversation_id: "conv_123"
|
|
94
|
+
summary: "Discussing future camping plans"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Benefits of Unified Storage
|
|
100
|
+
|
|
101
|
+
### 1. **Unified Search**
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// Search memories AND relationships together
|
|
105
|
+
remember_search_memory({
|
|
106
|
+
query: "camping trips",
|
|
107
|
+
include_relationships: true
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
// Returns:
|
|
111
|
+
{
|
|
112
|
+
memories: [
|
|
113
|
+
{ id: "mem_abc123", content: "Yosemite camping...", relationships: ["rel_xyz789"] }
|
|
114
|
+
],
|
|
115
|
+
relationships: [
|
|
116
|
+
{ id: "rel_xyz789", type: "inspired_by", observation: "Yosemite inspired Sequoia..." }
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Single Weaviate query!
|
|
121
|
+
const results = await weaviateClient
|
|
122
|
+
.collection(`Memory_${user_id}`)
|
|
123
|
+
.query.nearText("camping trips", {
|
|
124
|
+
// No doc_type filter - get both memories and relationships
|
|
125
|
+
limit: 20
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 2. **Relationship Discovery**
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
// Find relationships by observation text
|
|
133
|
+
remember_search_memory({
|
|
134
|
+
query: "what inspired my Sequoia trip?",
|
|
135
|
+
doc_types: ["relationship"] // Only search relationships
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
// Weaviate can semantically search relationship observations
|
|
139
|
+
// Returns: "Yosemite trip inspired Sequoia trip"
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 3. **Graph Queries**
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// Get memory with all its relationships in one query
|
|
146
|
+
async function getMemoryWithRelationships(memory_id: string, user_id: string) {
|
|
147
|
+
const memory = await weaviateClient
|
|
148
|
+
.collection(`Memory_${user_id}`)
|
|
149
|
+
.data.getById(memory_id);
|
|
150
|
+
|
|
151
|
+
// Get related relationships (same collection!)
|
|
152
|
+
const relationships = await weaviateClient
|
|
153
|
+
.collection(`Memory_${user_id}`)
|
|
154
|
+
.query.fetch({
|
|
155
|
+
where: {
|
|
156
|
+
operator: 'And',
|
|
157
|
+
operands: [
|
|
158
|
+
{ path: 'doc_type', operator: 'Equal', valueText: 'relationship' },
|
|
159
|
+
{ path: 'memory_ids', operator: 'ContainsAny', valueTextArray: [memory_id] }
|
|
160
|
+
]
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
memory,
|
|
166
|
+
relationships
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 4. **Contextual Search**
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
// "Show me camping memories and how they're connected"
|
|
175
|
+
const results = await weaviateClient
|
|
176
|
+
.collection(`Memory_${user_id}`)
|
|
177
|
+
.query.nearText("camping", {
|
|
178
|
+
limit: 20
|
|
179
|
+
// Gets both memories and relationships about camping
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Filter by type
|
|
183
|
+
const memories = results.filter(r => r.doc_type === 'memory');
|
|
184
|
+
const relationships = results.filter(r => r.doc_type === 'relationship');
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Schema Design
|
|
190
|
+
|
|
191
|
+
### Unified Schema with Discriminator
|
|
192
|
+
|
|
193
|
+
```yaml
|
|
194
|
+
Memory_{user_id} Collection Schema:
|
|
195
|
+
# Common fields (all documents)
|
|
196
|
+
doc_type: string # "memory" or "relationship"
|
|
197
|
+
user_id: string
|
|
198
|
+
created_at: datetime
|
|
199
|
+
updated_at: datetime
|
|
200
|
+
weight: float
|
|
201
|
+
trust: float
|
|
202
|
+
tags: array
|
|
203
|
+
|
|
204
|
+
# Memory-specific fields (when doc_type = "memory")
|
|
205
|
+
content: text
|
|
206
|
+
title: string
|
|
207
|
+
type: string
|
|
208
|
+
location: object
|
|
209
|
+
context: object
|
|
210
|
+
relationships: array # IDs of relationship documents
|
|
211
|
+
|
|
212
|
+
# Relationship-specific fields (when doc_type = "relationship")
|
|
213
|
+
memory_ids: array # IDs of connected memories
|
|
214
|
+
relationship_type: string
|
|
215
|
+
observation: text
|
|
216
|
+
strength: float
|
|
217
|
+
confidence: float
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Weaviate Configuration**:
|
|
221
|
+
```typescript
|
|
222
|
+
await weaviateClient.collections.create({
|
|
223
|
+
name: `Memory_${user_id}`,
|
|
224
|
+
properties: [
|
|
225
|
+
// Common
|
|
226
|
+
{ name: 'doc_type', dataType: 'text' },
|
|
227
|
+
{ name: 'user_id', dataType: 'text' },
|
|
228
|
+
{ name: 'weight', dataType: 'number' },
|
|
229
|
+
{ name: 'trust', dataType: 'number' },
|
|
230
|
+
|
|
231
|
+
// Memory fields
|
|
232
|
+
{ name: 'content', dataType: 'text' },
|
|
233
|
+
{ name: 'title', dataType: 'text' },
|
|
234
|
+
{ name: 'type', dataType: 'text' },
|
|
235
|
+
|
|
236
|
+
// Relationship fields
|
|
237
|
+
{ name: 'memory_ids', dataType: 'text[]' },
|
|
238
|
+
{ name: 'relationship_type', dataType: 'text' },
|
|
239
|
+
{ name: 'observation', dataType: 'text' },
|
|
240
|
+
{ name: 'strength', dataType: 'number' },
|
|
241
|
+
|
|
242
|
+
// ... other fields
|
|
243
|
+
],
|
|
244
|
+
vectorizers: weaviate.configure.vectorizer.text2VecOpenAI({
|
|
245
|
+
model: 'text-embedding-3-small',
|
|
246
|
+
// Vectorize both memory content and relationship observations
|
|
247
|
+
sourceProperties: ['content', 'observation']
|
|
248
|
+
})
|
|
249
|
+
});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Query Patterns
|
|
255
|
+
|
|
256
|
+
### Search Memories Only
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
remember_search_memory({
|
|
260
|
+
query: "camping",
|
|
261
|
+
doc_types: ["memory"] // Filter to memories only
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
// Weaviate query
|
|
265
|
+
await weaviateClient
|
|
266
|
+
.collection(`Memory_${user_id}`)
|
|
267
|
+
.query.nearText("camping", {
|
|
268
|
+
where: { path: 'doc_type', operator: 'Equal', valueText: 'memory' }
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Search Relationships Only
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
remember_search_relationship({
|
|
276
|
+
query: "inspired by",
|
|
277
|
+
limit: 10
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
// Weaviate query
|
|
281
|
+
await weaviateClient
|
|
282
|
+
.collection(`Memory_${user_id}`)
|
|
283
|
+
.query.nearText("inspired by", {
|
|
284
|
+
where: { path: 'doc_type', operator: 'Equal', valueText: 'relationship' }
|
|
285
|
+
});
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Search Both
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
remember_search_memory({
|
|
292
|
+
query: "camping",
|
|
293
|
+
include_relationships: true // Don't filter by doc_type
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
// Weaviate query
|
|
297
|
+
await weaviateClient
|
|
298
|
+
.collection(`Memory_${user_id}`)
|
|
299
|
+
.query.nearText("camping", {
|
|
300
|
+
// No doc_type filter - returns both
|
|
301
|
+
});
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Recommendation
|
|
307
|
+
|
|
308
|
+
**Store relationships in Memory collection with `doc_type` discriminator**
|
|
309
|
+
|
|
310
|
+
### Rationale
|
|
311
|
+
|
|
312
|
+
1. **Unified Search**: Query memories and relationships together
|
|
313
|
+
2. **Better UX**: "Show camping memories and connections" in one query
|
|
314
|
+
3. **Semantic Search**: Search relationship observations semantically
|
|
315
|
+
4. **Fewer Collections**: Simpler management
|
|
316
|
+
5. **Graph Queries**: Get memory with relationships efficiently
|
|
317
|
+
|
|
318
|
+
### Trade-offs
|
|
319
|
+
|
|
320
|
+
- Need to filter by `doc_type` when querying specific types
|
|
321
|
+
- Mixed schemas in one collection
|
|
322
|
+
- Slightly more complex schema
|
|
323
|
+
|
|
324
|
+
**Verdict**: Benefits far outweigh trade-offs
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Updated Collection Strategy
|
|
329
|
+
|
|
330
|
+
### Weaviate Collections (FINAL)
|
|
331
|
+
|
|
332
|
+
```
|
|
333
|
+
1. Memory_{user_id}
|
|
334
|
+
- Stores both memories AND relationships
|
|
335
|
+
- doc_type field discriminates
|
|
336
|
+
- Unified semantic search
|
|
337
|
+
- Optimized for: content search, relationship discovery
|
|
338
|
+
|
|
339
|
+
2. Template_system
|
|
340
|
+
- Default templates (shared)
|
|
341
|
+
- Immutable, curated
|
|
342
|
+
- Optimized for: template matching
|
|
343
|
+
|
|
344
|
+
3. Template_{user_id} (lazy create)
|
|
345
|
+
- User's custom templates
|
|
346
|
+
- Private, modifiable
|
|
347
|
+
- Optimized for: template matching
|
|
348
|
+
|
|
349
|
+
4. Audit_{user_id} (optional, lazy create)
|
|
350
|
+
- Audit logs, action logs
|
|
351
|
+
- Separate retention policies
|
|
352
|
+
- Optimized for: time-series queries
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**Simplified from 5 collections to 3-4 collections per user**
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
**Status**: Design Recommendation (FINAL)
|
|
360
|
+
**Decision**: Store relationships in Memory collection
|
|
361
|
+
**Benefit**: Unified search, better UX, fewer collections
|