@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,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory type definitions for remember-mcp
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Content types for memories
|
|
7
|
+
* Based on agent/design/content-types-expansion.md
|
|
8
|
+
*/
|
|
9
|
+
export type ContentType =
|
|
10
|
+
// Core types
|
|
11
|
+
| 'code'
|
|
12
|
+
| 'note'
|
|
13
|
+
| 'documentation'
|
|
14
|
+
| 'reference'
|
|
15
|
+
// Task & Planning
|
|
16
|
+
| 'todo'
|
|
17
|
+
| 'checklist'
|
|
18
|
+
| 'project'
|
|
19
|
+
| 'goal'
|
|
20
|
+
| 'habit'
|
|
21
|
+
// Communication
|
|
22
|
+
| 'email'
|
|
23
|
+
| 'conversation'
|
|
24
|
+
| 'meeting'
|
|
25
|
+
| 'person'
|
|
26
|
+
// Content & Media
|
|
27
|
+
| 'article'
|
|
28
|
+
| 'webpage'
|
|
29
|
+
| 'social'
|
|
30
|
+
| 'image'
|
|
31
|
+
| 'video'
|
|
32
|
+
| 'audio'
|
|
33
|
+
| 'transcript'
|
|
34
|
+
| 'presentation'
|
|
35
|
+
| 'spreadsheet'
|
|
36
|
+
| 'pdf'
|
|
37
|
+
// Creative
|
|
38
|
+
| 'screenplay'
|
|
39
|
+
| 'recipe'
|
|
40
|
+
| 'idea'
|
|
41
|
+
| 'quote'
|
|
42
|
+
// Personal
|
|
43
|
+
| 'journal'
|
|
44
|
+
| 'memory'
|
|
45
|
+
| 'event'
|
|
46
|
+
// Organizational
|
|
47
|
+
| 'bookmark'
|
|
48
|
+
| 'form'
|
|
49
|
+
| 'location'
|
|
50
|
+
// Business
|
|
51
|
+
| 'invoice'
|
|
52
|
+
| 'contract'
|
|
53
|
+
// System
|
|
54
|
+
| 'system'
|
|
55
|
+
| 'action'
|
|
56
|
+
| 'audit'
|
|
57
|
+
| 'history';
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* GPS coordinates
|
|
61
|
+
*/
|
|
62
|
+
export interface GPSCoordinates {
|
|
63
|
+
latitude: number;
|
|
64
|
+
longitude: number;
|
|
65
|
+
accuracy?: number; // Accuracy in meters
|
|
66
|
+
altitude?: number;
|
|
67
|
+
timestamp: string; // ISO 8601 datetime
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Address information
|
|
72
|
+
*/
|
|
73
|
+
export interface Address {
|
|
74
|
+
formatted: string; // Full formatted address
|
|
75
|
+
street?: string;
|
|
76
|
+
city?: string;
|
|
77
|
+
state?: string;
|
|
78
|
+
country?: string;
|
|
79
|
+
postal_code?: string;
|
|
80
|
+
timezone?: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Location information (from platform cookies)
|
|
85
|
+
*/
|
|
86
|
+
export interface Location {
|
|
87
|
+
gps: GPSCoordinates | null;
|
|
88
|
+
address: Address | null;
|
|
89
|
+
source: 'gps' | 'ip' | 'manual' | 'cached' | 'unavailable';
|
|
90
|
+
confidence: number; // 0-1
|
|
91
|
+
is_approximate: boolean;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Conversation participant
|
|
96
|
+
*/
|
|
97
|
+
export interface Participant {
|
|
98
|
+
user_id: string;
|
|
99
|
+
role: 'user' | 'assistant' | 'system';
|
|
100
|
+
name?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Source information
|
|
105
|
+
*/
|
|
106
|
+
export interface Source {
|
|
107
|
+
type: 'conversation' | 'import' | 'inference' | 'manual' | 'api';
|
|
108
|
+
platform?: string; // web, mobile, api
|
|
109
|
+
client?: string;
|
|
110
|
+
version?: string;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Environment information
|
|
115
|
+
*/
|
|
116
|
+
export interface Environment {
|
|
117
|
+
location?: Location;
|
|
118
|
+
device?: string;
|
|
119
|
+
user_agent?: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Context information about how/when memory was created
|
|
124
|
+
*/
|
|
125
|
+
export interface MemoryContext {
|
|
126
|
+
conversation_id?: string;
|
|
127
|
+
conversation_title?: string;
|
|
128
|
+
turn_number?: number;
|
|
129
|
+
summary?: string; // Brief summary for quick retrieval
|
|
130
|
+
participants?: Participant[];
|
|
131
|
+
timestamp: string; // ISO 8601 datetime
|
|
132
|
+
timezone?: string;
|
|
133
|
+
source: Source;
|
|
134
|
+
environment?: Environment;
|
|
135
|
+
tags?: string[];
|
|
136
|
+
notes?: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Core Memory interface
|
|
141
|
+
* Based on agent/design/requirements-enhancements.md
|
|
142
|
+
*/
|
|
143
|
+
export interface Memory {
|
|
144
|
+
// Core Identity
|
|
145
|
+
id: string; // UUID from Weaviate
|
|
146
|
+
user_id: string;
|
|
147
|
+
doc_type: 'memory'; // Discriminator for unified collection
|
|
148
|
+
|
|
149
|
+
// Content
|
|
150
|
+
content: string; // Main memory content (vectorized)
|
|
151
|
+
title?: string;
|
|
152
|
+
summary?: string;
|
|
153
|
+
type: ContentType;
|
|
154
|
+
|
|
155
|
+
// Significance & Trust
|
|
156
|
+
weight: number; // 0-1, significance/priority
|
|
157
|
+
trust: number; // 0-1, access control level
|
|
158
|
+
confidence?: number; // 0-1, system confidence in accuracy
|
|
159
|
+
|
|
160
|
+
// Location (from platform)
|
|
161
|
+
location: Location;
|
|
162
|
+
|
|
163
|
+
// Context
|
|
164
|
+
context: MemoryContext;
|
|
165
|
+
|
|
166
|
+
// Relationships
|
|
167
|
+
relationships: string[]; // IDs of relationship documents
|
|
168
|
+
|
|
169
|
+
// Access Tracking (for weight calculation)
|
|
170
|
+
access_count: number;
|
|
171
|
+
last_accessed_at?: string; // ISO 8601 datetime
|
|
172
|
+
access_frequency?: number; // Accesses per day
|
|
173
|
+
|
|
174
|
+
// Metadata
|
|
175
|
+
created_at: string; // ISO 8601 datetime
|
|
176
|
+
updated_at: string; // ISO 8601 datetime
|
|
177
|
+
version: number;
|
|
178
|
+
|
|
179
|
+
// Organization
|
|
180
|
+
tags: string[];
|
|
181
|
+
category?: string;
|
|
182
|
+
references?: string[]; // Source URLs
|
|
183
|
+
|
|
184
|
+
// Template Integration (optional)
|
|
185
|
+
template_id?: string;
|
|
186
|
+
template_version?: string;
|
|
187
|
+
structured_content?: Record<string, any>;
|
|
188
|
+
|
|
189
|
+
// Computed Weight (for search ranking)
|
|
190
|
+
base_weight: number; // User-specified
|
|
191
|
+
computed_weight?: number; // Calculated with access multipliers
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Relationship interface
|
|
196
|
+
* Stored in same collection as memories with doc_type: "relationship"
|
|
197
|
+
*/
|
|
198
|
+
export interface Relationship {
|
|
199
|
+
// Core Identity
|
|
200
|
+
id: string;
|
|
201
|
+
user_id: string;
|
|
202
|
+
doc_type: 'relationship'; // Discriminator
|
|
203
|
+
|
|
204
|
+
// Connection
|
|
205
|
+
memory_ids: string[]; // 2...N memory IDs
|
|
206
|
+
relationship_type: string; // Free-form: "causes", "contradicts", "inspired_by", etc.
|
|
207
|
+
|
|
208
|
+
// Observation
|
|
209
|
+
observation: string; // Description of the connection (vectorized)
|
|
210
|
+
strength: number; // 0-1
|
|
211
|
+
confidence: number; // 0-1
|
|
212
|
+
|
|
213
|
+
// Context
|
|
214
|
+
context: MemoryContext;
|
|
215
|
+
|
|
216
|
+
// Metadata
|
|
217
|
+
created_at: string;
|
|
218
|
+
updated_at: string;
|
|
219
|
+
version: number;
|
|
220
|
+
tags: string[];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Union type for documents in Memory collection
|
|
225
|
+
*/
|
|
226
|
+
export type MemoryDocument = Memory | Relationship;
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Partial memory for updates
|
|
230
|
+
*/
|
|
231
|
+
export type MemoryUpdate = Partial<Omit<Memory, 'id' | 'user_id' | 'doc_type' | 'created_at' | 'version'>>;
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Partial relationship for updates
|
|
235
|
+
*/
|
|
236
|
+
export type RelationshipUpdate = Partial<Omit<Relationship, 'id' | 'user_id' | 'doc_type' | 'created_at' | 'version'>>;
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Search filters
|
|
240
|
+
*/
|
|
241
|
+
export interface SearchFilters {
|
|
242
|
+
types?: ContentType[];
|
|
243
|
+
tags?: string[];
|
|
244
|
+
weight_min?: number;
|
|
245
|
+
weight_max?: number;
|
|
246
|
+
trust_min?: number;
|
|
247
|
+
trust_max?: number;
|
|
248
|
+
date_from?: string;
|
|
249
|
+
date_to?: string;
|
|
250
|
+
location_near?: GPSCoordinates;
|
|
251
|
+
location_radius_meters?: number;
|
|
252
|
+
has_relationships?: boolean;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Search options
|
|
257
|
+
*/
|
|
258
|
+
export interface SearchOptions {
|
|
259
|
+
query: string;
|
|
260
|
+
alpha?: number; // 0-1, balance between semantic (1.0) and keyword (0.0)
|
|
261
|
+
filters?: SearchFilters;
|
|
262
|
+
include_relationships?: boolean;
|
|
263
|
+
limit?: number;
|
|
264
|
+
offset?: number;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Search result
|
|
269
|
+
*/
|
|
270
|
+
export interface SearchResult {
|
|
271
|
+
memories: Memory[];
|
|
272
|
+
relationships?: Relationship[];
|
|
273
|
+
total: number;
|
|
274
|
+
offset: number;
|
|
275
|
+
limit: number;
|
|
276
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { config } from '../config.js';
|
|
2
|
+
|
|
3
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
4
|
+
|
|
5
|
+
const LOG_LEVELS: Record<LogLevel, number> = {
|
|
6
|
+
debug: 0,
|
|
7
|
+
info: 1,
|
|
8
|
+
warn: 2,
|
|
9
|
+
error: 3,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const currentLevel = LOG_LEVELS[config.server.logLevel as LogLevel] ?? LOG_LEVELS.info;
|
|
13
|
+
|
|
14
|
+
function shouldLog(level: LogLevel): boolean {
|
|
15
|
+
return LOG_LEVELS[level] >= currentLevel;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const logger = {
|
|
19
|
+
debug: (message: string, ...args: any[]) => {
|
|
20
|
+
if (shouldLog('debug')) {
|
|
21
|
+
console.debug(`[DEBUG] ${message}`, ...args);
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
info: (message: string, ...args: any[]) => {
|
|
26
|
+
if (shouldLog('info')) {
|
|
27
|
+
console.info(`[INFO] ${message}`, ...args);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
warn: (message: string, ...args: any[]) => {
|
|
32
|
+
if (shouldLog('warn')) {
|
|
33
|
+
console.warn(`[WARN] ${message}`, ...args);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
error: (message: string, ...args: any[]) => {
|
|
38
|
+
if (shouldLog('error')) {
|
|
39
|
+
console.error(`[ERROR] ${message}`, ...args);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll } from '@jest/globals';
|
|
2
|
+
import {
|
|
3
|
+
initWeaviateClient,
|
|
4
|
+
testWeaviateConnection,
|
|
5
|
+
sanitizeUserId,
|
|
6
|
+
getMemoryCollectionName,
|
|
7
|
+
getTemplateCollectionName,
|
|
8
|
+
getAuditCollectionName,
|
|
9
|
+
} from '../../src/weaviate/client.js';
|
|
10
|
+
|
|
11
|
+
describe('Weaviate Client', () => {
|
|
12
|
+
describe('User ID Sanitization', () => {
|
|
13
|
+
it('should sanitize email addresses', () => {
|
|
14
|
+
expect(sanitizeUserId('user@example.com')).toBe('User_example_com');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should sanitize user IDs with hyphens', () => {
|
|
18
|
+
expect(sanitizeUserId('user-123')).toBe('User_123');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should handle IDs starting with numbers', () => {
|
|
22
|
+
expect(sanitizeUserId('123user')).toBe('_123user');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should handle special characters', () => {
|
|
26
|
+
expect(sanitizeUserId('user!@#$%123')).toBe('User_____123');
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('Collection Name Generation', () => {
|
|
31
|
+
it('should generate memory collection names', () => {
|
|
32
|
+
expect(getMemoryCollectionName('user123')).toBe('Memory_User123');
|
|
33
|
+
expect(getMemoryCollectionName('user@test.com')).toBe('Memory_User_test_com');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should generate template collection names', () => {
|
|
37
|
+
expect(getTemplateCollectionName('user123')).toBe('Template_User123');
|
|
38
|
+
expect(getTemplateCollectionName('user@test.com')).toBe('Template_User_test_com');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should generate audit collection names', () => {
|
|
42
|
+
expect(getAuditCollectionName('user123')).toBe('Audit_User123');
|
|
43
|
+
expect(getAuditCollectionName('user@test.com')).toBe('Audit_User_test_com');
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Integration tests (require Weaviate instance)
|
|
48
|
+
describe.skip('Weaviate Connection', () => {
|
|
49
|
+
beforeAll(async () => {
|
|
50
|
+
await initWeaviateClient();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should initialize client', async () => {
|
|
54
|
+
const result = await testWeaviateConnection();
|
|
55
|
+
expect(result).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import weaviate, { WeaviateClient } from 'weaviate-client';
|
|
2
|
+
import { config } from '../config.js';
|
|
3
|
+
|
|
4
|
+
let client: WeaviateClient | null = null;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Initialize Weaviate client
|
|
8
|
+
*/
|
|
9
|
+
export async function initWeaviateClient(): Promise<WeaviateClient> {
|
|
10
|
+
if (client) {
|
|
11
|
+
return client;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Weaviate v3 client initialization
|
|
15
|
+
client = await weaviate.connectToWeaviateCloud(config.weaviate.url, {
|
|
16
|
+
authCredentials: config.weaviate.apiKey
|
|
17
|
+
? new weaviate.ApiKey(config.weaviate.apiKey)
|
|
18
|
+
: undefined,
|
|
19
|
+
headers: config.openai.apiKey
|
|
20
|
+
? { 'X-OpenAI-Api-Key': config.openai.apiKey }
|
|
21
|
+
: undefined,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
console.log('[Weaviate] Client initialized');
|
|
25
|
+
return client;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Get Weaviate client instance
|
|
30
|
+
*/
|
|
31
|
+
export function getWeaviateClient(): WeaviateClient {
|
|
32
|
+
if (!client) {
|
|
33
|
+
throw new Error('Weaviate client not initialized. Call initWeaviateClient() first.');
|
|
34
|
+
}
|
|
35
|
+
return client;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Test Weaviate connection
|
|
40
|
+
*/
|
|
41
|
+
export async function testWeaviateConnection(): Promise<boolean> {
|
|
42
|
+
try {
|
|
43
|
+
const weaviateClient = getWeaviateClient();
|
|
44
|
+
const isReady = await weaviateClient.isReady();
|
|
45
|
+
console.log('[Weaviate] Connection successful, ready:', isReady);
|
|
46
|
+
return isReady;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.error('[Weaviate] Connection failed:', error);
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Sanitize user_id for collection name
|
|
55
|
+
* Weaviate collection names must start with uppercase letter and contain only alphanumeric
|
|
56
|
+
*/
|
|
57
|
+
export function sanitizeUserId(userId: string): string {
|
|
58
|
+
// Remove special characters, keep alphanumeric
|
|
59
|
+
let sanitized = userId.replace(/[^a-zA-Z0-9]/g, '_');
|
|
60
|
+
|
|
61
|
+
// If starts with number, prepend underscore
|
|
62
|
+
if (/^[0-9]/.test(sanitized)) {
|
|
63
|
+
sanitized = '_' + sanitized;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Ensure starts with uppercase letter
|
|
67
|
+
return sanitized.charAt(0).toUpperCase() + sanitized.slice(1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get collection name for user's memories
|
|
72
|
+
*/
|
|
73
|
+
export function getMemoryCollectionName(userId: string): string {
|
|
74
|
+
return `Memory_${sanitizeUserId(userId)}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get collection name for user's templates
|
|
79
|
+
*/
|
|
80
|
+
export function getTemplateCollectionName(userId: string): string {
|
|
81
|
+
return `Template_${sanitizeUserId(userId)}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Get collection name for user's audit logs
|
|
86
|
+
*/
|
|
87
|
+
export function getAuditCollectionName(userId: string): string {
|
|
88
|
+
return `Audit_${sanitizeUserId(userId)}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Check if collection exists
|
|
93
|
+
*/
|
|
94
|
+
export async function collectionExists(collectionName: string): Promise<boolean> {
|
|
95
|
+
try {
|
|
96
|
+
const weaviateClient = getWeaviateClient();
|
|
97
|
+
const exists = await weaviateClient.collections.exists(collectionName);
|
|
98
|
+
return exists;
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.error(`[Weaviate] Error checking collection ${collectionName}:`, error);
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Close Weaviate client connection
|
|
107
|
+
*/
|
|
108
|
+
export async function closeWeaviateClient(): Promise<void> {
|
|
109
|
+
if (client) {
|
|
110
|
+
// Weaviate client doesn't have explicit close method
|
|
111
|
+
client = null;
|
|
112
|
+
console.log('[Weaviate] Client closed');
|
|
113
|
+
}
|
|
114
|
+
}
|