universal-llm-client 4.0.0 → 4.2.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.
Files changed (127) hide show
  1. package/dist/ai-model.d.ts +20 -22
  2. package/dist/ai-model.d.ts.map +1 -1
  3. package/dist/ai-model.js +26 -23
  4. package/dist/ai-model.js.map +1 -1
  5. package/dist/client.d.ts +5 -5
  6. package/dist/client.d.ts.map +1 -1
  7. package/dist/client.js +17 -9
  8. package/dist/client.js.map +1 -1
  9. package/dist/http.d.ts +2 -0
  10. package/dist/http.d.ts.map +1 -1
  11. package/dist/http.js +1 -0
  12. package/dist/http.js.map +1 -1
  13. package/dist/index.d.ts +3 -3
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +4 -4
  16. package/dist/index.js.map +1 -1
  17. package/dist/interfaces.d.ts +49 -11
  18. package/dist/interfaces.d.ts.map +1 -1
  19. package/dist/interfaces.js +14 -0
  20. package/dist/interfaces.js.map +1 -1
  21. package/dist/providers/anthropic.d.ts +56 -0
  22. package/dist/providers/anthropic.d.ts.map +1 -0
  23. package/dist/providers/anthropic.js +524 -0
  24. package/dist/providers/anthropic.js.map +1 -0
  25. package/dist/providers/google.d.ts +5 -0
  26. package/dist/providers/google.d.ts.map +1 -1
  27. package/dist/providers/google.js +64 -8
  28. package/dist/providers/google.js.map +1 -1
  29. package/dist/providers/index.d.ts +1 -0
  30. package/dist/providers/index.d.ts.map +1 -1
  31. package/dist/providers/index.js +1 -0
  32. package/dist/providers/index.js.map +1 -1
  33. package/dist/providers/ollama.d.ts.map +1 -1
  34. package/dist/providers/ollama.js +38 -11
  35. package/dist/providers/ollama.js.map +1 -1
  36. package/dist/providers/openai.d.ts.map +1 -1
  37. package/dist/providers/openai.js +9 -7
  38. package/dist/providers/openai.js.map +1 -1
  39. package/dist/router.d.ts +13 -33
  40. package/dist/router.d.ts.map +1 -1
  41. package/dist/router.js +33 -57
  42. package/dist/router.js.map +1 -1
  43. package/dist/stream-decoder.d.ts +29 -2
  44. package/dist/stream-decoder.d.ts.map +1 -1
  45. package/dist/stream-decoder.js +39 -11
  46. package/dist/stream-decoder.js.map +1 -1
  47. package/dist/structured-output.d.ts +107 -181
  48. package/dist/structured-output.d.ts.map +1 -1
  49. package/dist/structured-output.js +137 -192
  50. package/dist/structured-output.js.map +1 -1
  51. package/dist/zod-adapter.d.ts +44 -0
  52. package/dist/zod-adapter.d.ts.map +1 -0
  53. package/dist/zod-adapter.js +61 -0
  54. package/dist/zod-adapter.js.map +1 -0
  55. package/package.json +9 -1
  56. package/src/ai-model.ts +350 -0
  57. package/src/auditor.ts +213 -0
  58. package/src/client.ts +402 -0
  59. package/src/debug/debug-google-streaming.ts +97 -0
  60. package/src/debug/debug-tool-execution.ts +86 -0
  61. package/src/debug/test-lmstudio-tools.ts +155 -0
  62. package/src/demos/README.md +47 -0
  63. package/src/demos/basic/universal-llm-examples.ts +161 -0
  64. package/src/demos/mcp/astrid-memory-demo.ts +295 -0
  65. package/src/demos/mcp/astrid-persona-memory.ts +357 -0
  66. package/src/demos/mcp/mcp-mongodb-demo.ts +275 -0
  67. package/src/demos/mcp/simple-astrid-memory.ts +148 -0
  68. package/src/demos/mcp/simple-mcp-demo.ts +68 -0
  69. package/src/demos/mcp/working-mcp-demo.ts +62 -0
  70. package/src/demos/model-alias-demo.ts +0 -0
  71. package/src/demos/tools/RAG_MEMORY_INTEGRATION.md +267 -0
  72. package/src/demos/tools/astrid-memory-demo.ts +270 -0
  73. package/src/demos/tools/astrid-production-memory-clean.ts +785 -0
  74. package/src/demos/tools/astrid-production-memory.ts +558 -0
  75. package/src/demos/tools/basic-translation-test.ts +66 -0
  76. package/src/demos/tools/chromadb-similarity-tuning.ts +390 -0
  77. package/src/demos/tools/clean-multilingual-conversation.ts +209 -0
  78. package/src/demos/tools/clean-translation-test.ts +119 -0
  79. package/src/demos/tools/clean-universal-multilingual-test.ts +131 -0
  80. package/src/demos/tools/complete-rag-demo.ts +369 -0
  81. package/src/demos/tools/complete-tool-demo.ts +132 -0
  82. package/src/demos/tools/demo-tool-calling.ts +124 -0
  83. package/src/demos/tools/dynamic-language-switching-test.ts +251 -0
  84. package/src/demos/tools/hybrid-thinking-test.ts +154 -0
  85. package/src/demos/tools/memory-integration-test.ts +420 -0
  86. package/src/demos/tools/multilingual-memory-system.ts +802 -0
  87. package/src/demos/tools/ondemand-translation-demo.ts +655 -0
  88. package/src/demos/tools/production-tool-demo.ts +245 -0
  89. package/src/demos/tools/revolutionary-multilingual-test.ts +151 -0
  90. package/src/demos/tools/rigorous-language-analysis.ts +218 -0
  91. package/src/demos/tools/test-universal-memory-system.ts +126 -0
  92. package/src/demos/tools/translation-integration-guide.ts +346 -0
  93. package/src/demos/tools/universal-memory-system.ts +560 -0
  94. package/src/http.ts +247 -0
  95. package/src/index.ts +161 -0
  96. package/src/interfaces.ts +657 -0
  97. package/src/mcp.ts +345 -0
  98. package/src/providers/anthropic.ts +762 -0
  99. package/src/providers/google.ts +620 -0
  100. package/src/providers/index.ts +8 -0
  101. package/src/providers/ollama.ts +469 -0
  102. package/src/providers/openai.ts +392 -0
  103. package/src/router.ts +780 -0
  104. package/src/stream-decoder.ts +361 -0
  105. package/src/structured-output.ts +759 -0
  106. package/src/test-scripts/test-advanced-tools.ts +310 -0
  107. package/src/test-scripts/test-google-streaming-enhanced.ts +147 -0
  108. package/src/test-scripts/test-google-streaming.ts +63 -0
  109. package/src/test-scripts/test-google-system-prompt-comprehensive.ts +189 -0
  110. package/src/test-scripts/test-mcp-config.ts +28 -0
  111. package/src/test-scripts/test-mcp-connection.ts +29 -0
  112. package/src/test-scripts/test-system-message-positions.ts +163 -0
  113. package/src/test-scripts/test-system-prompt-improvement-demo.ts +83 -0
  114. package/src/test-scripts/test-tool-calling.ts +231 -0
  115. package/src/tests/ai-model.test.ts +1614 -0
  116. package/src/tests/auditor.test.ts +224 -0
  117. package/src/tests/http.test.ts +200 -0
  118. package/src/tests/interfaces.test.ts +117 -0
  119. package/src/tests/providers/google.test.ts +660 -0
  120. package/src/tests/providers/ollama.test.ts +954 -0
  121. package/src/tests/providers/openai.test.ts +1122 -0
  122. package/src/tests/router.test.ts +254 -0
  123. package/src/tests/stream-decoder.test.ts +179 -0
  124. package/src/tests/structured-output.test.ts +1450 -0
  125. package/src/tests/tools.test.ts +175 -0
  126. package/src/tools.ts +246 -0
  127. package/src/zod-adapter.ts +72 -0
@@ -0,0 +1,560 @@
1
+ /**
2
+ * Universal Memory System
3
+ *
4
+ * Demonstrates how to create a modular memory system that can work with any persona.
5
+ * Separates persona-specific prompts from universal tool/memory instructions.
6
+ */
7
+
8
+ import '@dotenvx/dotenvx/config';
9
+
10
+ import { AIModelFactory, ToolBuilder, LLMChatMessage } from '../../index';
11
+ import { ChromaDBService } from '../../../../../src/services/ChromaDBService.js';
12
+ import { DatabaseConnection } from '../../../../../src/database/connection.js';
13
+ import { UserModel, UserGender, UserSexualOrientation } from '../../../../../src/models/User.js';
14
+ import { AuraPersonaModel } from '../../../../../src/models/AuraPersona.js';
15
+ import { UserPersonaModel } from '../../../../../src/models/UserPersona.js';
16
+
17
+ interface PersonaConfig {
18
+ name: string;
19
+ personalityPrompt: string;
20
+ conversationStyle: string;
21
+ }
22
+
23
+ // Universal Memory System Instructions (persona-agnostic)
24
+ const UNIVERSAL_MEMORY_INSTRUCTIONS = `MEMORY SYSTEM INTEGRATION:
25
+ - Use recall_romantic_memories when:
26
+ * Starting a fresh conversation (no recent message history about the user)
27
+ * User references past conversations or shared experiences
28
+ * You need specific details about their preferences, background, or previous discussions
29
+ * Planning something personal or making recommendations that require knowing their interests
30
+ - Use store_romantic_memory for important personal details, emotions, preferences, meaningful experiences, dreams, fears, goals, or relationship milestones
31
+ - DO NOT store trivial information like weather comments, casual greetings, or mundane daily activities
32
+ - Store emotional context and relationship stage to build deeper connections over time
33
+
34
+ MULTI-ROUND TOOL EXECUTION STRATEGY:
35
+ - PREFER making multiple tool calls within the SAME response rather than separate LLM calls
36
+ - When you need information from multiple categories, call recall_romantic_memories multiple times in ONE response
37
+ - Example: If planning recommendations, call recall for "preferences", "values", and "fears" all at once
38
+ - This is computationally more efficient than making separate LLM calls
39
+ - Use targeted searches in parallel: specific query + category searches + fallback terms
40
+ - Gather ALL needed information in one go, then provide comprehensive response
41
+
42
+ MEMORY RECALL GUIDELINES:
43
+ - If recent messages contain the information you need, use that instead of recalling
44
+ - Only recall when you genuinely need information not available in the current conversation
45
+ - For specific scenarios, use targeted search terms:
46
+ * Restaurant/food recommendations: search "food diet preferences" or use category "preferences"
47
+ * Activity suggestions: search "hobbies interests activities" or use category "personal"
48
+ * Emotional support: search "fears concerns worries" or use category "fears"
49
+ * Career/work topics: search "work career goals" or use category "work"
50
+ - When in doubt, use category search instead of semantic search for broader recall
51
+ - Reference recalled memories naturally in your responses to show continuity
52
+
53
+ WHAT TO STORE:
54
+ āœ… Personal background, career, family situations
55
+ āœ… Dreams, goals, fears, deep emotions
56
+ āœ… Preferences in relationships, travel, lifestyle, diet, hobbies
57
+ āœ… Meaningful experiences that shaped them
58
+ āœ… Values, beliefs, personality traits
59
+ āœ… Relationship milestones and emotional moments
60
+
61
+ WHAT NOT TO STORE:
62
+ āŒ Small talk about weather, current time, basic greetings
63
+ āŒ Temporary mood states without deeper meaning
64
+ āŒ Random comments or jokes without personal significance
65
+ āŒ Generic compliments or surface-level observations
66
+ āŒ Technical details unless they reveal personal interests
67
+
68
+ Remember: Quality over quantity in memory storage. Store what matters, ignore what doesn't. Recall comprehensively when needed using MULTIPLE tool calls in ONE response.`;
69
+
70
+ // Different persona configurations
71
+ const PERSONA_CONFIGS: { [key: string]: PersonaConfig } = {
72
+ astrid: {
73
+ name: "Astrid",
74
+ personalityPrompt: "You are Astrid, a captivating Swedish model and influencer in a romantic relationship context.",
75
+ conversationStyle: `ROMANTIC CONVERSATION STYLE:
76
+ - Keep responses warm, engaging, and conversational (2-3 sentences ideal)
77
+ - Reference stored memories naturally to show you remember and care
78
+ - Ask follow-up questions that encourage deeper sharing
79
+ - Balance sophistication with authenticity
80
+ - Use your Swedish charm and model background to create engaging dialogue
81
+ - Show genuine interest in building deeper romantic connections`
82
+ },
83
+
84
+ maya: {
85
+ name: "Maya",
86
+ personalityPrompt: "You are Maya, a creative artist and free spirit who values deep emotional connections and authentic conversations.",
87
+ conversationStyle: `ARTISTIC CONVERSATION STYLE:
88
+ - Express yourself with creative flair and emotional depth
89
+ - Reference memories through an artistic lens
90
+ - Ask thought-provoking questions that inspire self-reflection
91
+ - Balance creativity with genuine empathy
92
+ - Use metaphors and imagery to create meaningful dialogue
93
+ - Encourage exploration of emotions and dreams`
94
+ },
95
+
96
+ sophia: {
97
+ name: "Sophia",
98
+ personalityPrompt: "You are Sophia, an intelligent professional who combines intellectual curiosity with emotional intelligence.",
99
+ conversationStyle: `INTELLECTUAL CONVERSATION STYLE:
100
+ - Engage with thoughtful analysis and genuine interest
101
+ - Reference memories to build comprehensive understanding
102
+ - Ask insightful questions that reveal deeper truths
103
+ - Balance intellect with warmth and care
104
+ - Use knowledge and wisdom to guide meaningful conversations
105
+ - Encourage growth through understanding and reflection`
106
+ },
107
+
108
+ luna: {
109
+ name: "Luna",
110
+ personalityPrompt: "You are Luna, a mystical and intuitive soul who connects deeply with emotions and spiritual aspects of life.",
111
+ conversationStyle: `MYSTICAL CONVERSATION STYLE:
112
+ - Connect on an intuitive and spiritual level
113
+ - Reference memories with emotional and energetic awareness
114
+ - Ask questions that explore inner wisdom and feelings
115
+ - Balance mysticism with practical empathy
116
+ - Use intuitive insights to create profound connections
117
+ - Encourage exploration of inner self and spiritual growth`
118
+ }
119
+ };
120
+
121
+ function createUniversalMemoryTools(
122
+ chromaService: ChromaDBService,
123
+ userMongoId: string,
124
+ userPersonaId: string,
125
+ basePersonaId: string
126
+ ) {
127
+ const storeMemoryTool = ToolBuilder.createTool<{
128
+ category: string;
129
+ information: string;
130
+ importance: 'low' | 'medium' | 'high';
131
+ emotional_context?: string;
132
+ relationship_stage?: string;
133
+ }>(
134
+ 'store_romantic_memory',
135
+ 'Store important personal information about the user to build deeper romantic connection',
136
+ {
137
+ properties: {
138
+ category: {
139
+ type: 'string',
140
+ description: 'Category of information to remember',
141
+ enum: ['personal', 'work', 'family', 'preferences', 'fears', 'relationships', 'dreams', 'values']
142
+ },
143
+ information: {
144
+ type: 'string',
145
+ description: 'The specific information to remember about the user'
146
+ },
147
+ importance: {
148
+ type: 'string',
149
+ enum: ['low', 'medium', 'high'],
150
+ description: 'How important this information is for building romantic connection'
151
+ },
152
+ emotional_context: {
153
+ type: 'string',
154
+ description: 'The emotional context when this was shared (e.g., excited, vulnerable, proud, nervous)'
155
+ },
156
+ relationship_stage: {
157
+ type: 'string',
158
+ description: 'Current relationship stage when this was shared (e.g., getting_to_know, building_trust, deepening_bond)'
159
+ }
160
+ },
161
+ required: ['category', 'information', 'importance']
162
+ },
163
+ async (args) => {
164
+ try {
165
+ const conversationId = `romantic_chat_${Date.now()}`;
166
+ const confidence = args.importance === 'high' ? 0.9 : args.importance === 'medium' ? 0.7 : 0.5;
167
+
168
+ const insightId = await chromaService.addInsight(
169
+ userMongoId,
170
+ args.information,
171
+ args.category,
172
+ conversationId,
173
+ confidence,
174
+ userPersonaId,
175
+ basePersonaId,
176
+ 'user_insight',
177
+ undefined,
178
+ args.emotional_context,
179
+ args.relationship_stage
180
+ );
181
+
182
+ console.log(`āœ… Memory stored successfully`);
183
+
184
+ return {
185
+ success: true,
186
+ insight_id: insightId,
187
+ message: `šŸ’¾ Stored ${args.importance} importance ${args.category}`,
188
+ emotional_note: args.emotional_context ? `Context: ${args.emotional_context}` : undefined
189
+ };
190
+ } catch (error) {
191
+ console.log(`āŒ Memory storage failed - ${(error as Error).message}`);
192
+ return {
193
+ success: false,
194
+ error: `Storage failed: ${(error as Error).message}`
195
+ };
196
+ }
197
+ }
198
+ );
199
+
200
+ const retrieveMemoryTool = ToolBuilder.createTool<{
201
+ search_query?: string;
202
+ category?: string;
203
+ limit?: number;
204
+ }>(
205
+ 'recall_romantic_memories',
206
+ 'Retrieve stored memories about the user to personalize romantic conversation. This tool performs a single search operation - if no results are found, try different search terms or categories in separate tool calls. Use search_query for semantic search, category for recent memories in that category, or leave both empty for most recent memories overall.',
207
+ {
208
+ properties: {
209
+ search_query: {
210
+ type: 'string',
211
+ description: 'Search for specific memories or topics using semantic similarity. Leave empty to get recent memories.'
212
+ },
213
+ category: {
214
+ type: 'string',
215
+ description: 'Filter by category to get most recent memories in that category',
216
+ enum: ['personal', 'work', 'family', 'preferences', 'fears', 'relationships', 'dreams', 'values']
217
+ },
218
+ limit: {
219
+ type: 'number',
220
+ description: 'Maximum memories to retrieve (default: 5)',
221
+ default: 5
222
+ }
223
+ }
224
+ },
225
+ async (args) => {
226
+ try {
227
+ console.log(`šŸ” Searching for "${args.search_query || args.category || 'all memories'}"`);
228
+ let insights;
229
+ let searchAttempts:any[] = [];
230
+
231
+ if (args.search_query) {
232
+ const result = await chromaService.searchSimilarInsights(
233
+ userMongoId,
234
+ args.search_query,
235
+ args.limit || 5
236
+ );
237
+ insights = result.insights;
238
+ searchAttempts.push(`search "${args.search_query}": ${insights.length} results`);
239
+ console.log(` šŸ“Š Search query found ${insights.length} memories`);
240
+ if (result.stats) {
241
+ console.log(` šŸ“ˆ Search stats: avg similarity ${result.stats.averageSimilarity?.toFixed(3)}, top ${result.stats.topSimilarity?.toFixed(3)}`);
242
+ }
243
+ } else if (args.category) {
244
+ insights = await chromaService.getUserInsightsByCategory(
245
+ userMongoId,
246
+ args.category,
247
+ userPersonaId,
248
+ args.limit || 5
249
+ );
250
+ searchAttempts.push(`category "${args.category}": ${insights.length} results`);
251
+ console.log(` šŸ“Š Category filter found ${insights.length} memories`);
252
+ } else {
253
+ insights = await chromaService.getUserInsightsByCategory(
254
+ userMongoId,
255
+ undefined,
256
+ userPersonaId,
257
+ args.limit || 5
258
+ );
259
+ searchAttempts.push(`recent memories: ${insights.length} results`);
260
+ console.log(` šŸ“Š Recent memories found ${insights.length} memories`);
261
+ }
262
+
263
+ if (insights.length > 0) {
264
+ console.log(` āœ… Successfully retrieved ${insights.length} memories`);
265
+ insights.slice(0, 3).forEach((insight, i) => {
266
+ const category = insight.metadata?.category || 'unknown';
267
+ console.log(` ${i + 1}. [${category.toUpperCase()}] ${insight.content.substring(0, 100)}...`);
268
+ });
269
+ } else {
270
+ console.log(` āš ļø No memories found despite all search attempts`);
271
+ }
272
+
273
+ return {
274
+ memories: insights.map(insight => ({
275
+ category: insight.metadata?.category || 'unknown',
276
+ information: insight.content,
277
+ emotional_context: insight.metadata?.emotionalContext || undefined,
278
+ relationship_stage: insight.metadata?.relationshipStage || undefined,
279
+ confidence: parseFloat(insight.metadata?.confidence || '0'),
280
+ stored_date: insight.metadata?.extractedAt?.split('T')[0] || 'unknown',
281
+ extraction_type: insight.metadata?.extractionType || 'unknown'
282
+ })),
283
+ total_found: insights.length,
284
+ search_context: {
285
+ query: args.search_query,
286
+ category: args.category,
287
+ search_attempts: searchAttempts
288
+ }
289
+ };
290
+ } catch (error) {
291
+ console.log(` āŒ Memory recall failed - ${(error as Error).message}`);
292
+ return {
293
+ memories: [],
294
+ error: `Recall failed: ${(error as Error).message}`,
295
+ total_found: 0
296
+ };
297
+ }
298
+ }
299
+ );
300
+
301
+ return [storeMemoryTool, retrieveMemoryTool];
302
+ }
303
+
304
+ function createPersonaSystemPrompt(personaKey: string): string {
305
+ const config = PERSONA_CONFIGS[personaKey];
306
+ if (!config) {
307
+ throw new Error(`Unknown persona: ${personaKey}`);
308
+ }
309
+
310
+ return `${config.personalityPrompt}
311
+
312
+ ${config.conversationStyle}
313
+
314
+ ${UNIVERSAL_MEMORY_INSTRUCTIONS}`;
315
+ }
316
+
317
+ async function createTestUser(userId: string): Promise<boolean> {
318
+ try {
319
+ const existingUser = await UserModel.findOne({ userId });
320
+ if (existingUser) {
321
+ console.log(`āœ… Demo user ${userId} already exists`);
322
+ return true;
323
+ }
324
+
325
+ const demoUser = new UserModel({
326
+ userId,
327
+ preferences: {
328
+ userName: 'Sam (Universal Demo)',
329
+ userGender: UserGender.MALE,
330
+ userSexualOrientation: UserSexualOrientation.STRAIGHT,
331
+ preferredLanguage: 'en',
332
+ interests: ['photography', 'travel', 'music'],
333
+ preferredAgeGroup: '25-34'
334
+ }
335
+ });
336
+
337
+ await demoUser.save();
338
+ console.log(`āœ… Created test user: ${userId}`);
339
+ return true;
340
+ } catch (error) {
341
+ console.error(`āŒ Failed to create test user: ${(error as Error).message}`);
342
+ return false;
343
+ }
344
+ }
345
+
346
+ async function setupUniversalPersonas(userId: string, userMongoId: string): Promise<{ userPersonaId: string, basePersonaId: string } | null> {
347
+ try {
348
+ console.log('šŸ” Setting up universal persona system...');
349
+
350
+ const anyPersona = await AuraPersonaModel.findOne({});
351
+ if (!anyPersona) {
352
+ throw new Error('No personas found in database');
353
+ }
354
+ console.log(`āœ… Using base persona: ${anyPersona.name} (${anyPersona._id})`);
355
+
356
+ let userPersona = await UserPersonaModel.findOne({
357
+ userId: userMongoId,
358
+ basePersonaId: anyPersona._id
359
+ });
360
+
361
+ if (!userPersona) {
362
+ console.log('šŸ‘¤ Creating Universal UserPersona relationship...');
363
+
364
+ userPersona = new UserPersonaModel({
365
+ userId: userMongoId,
366
+ basePersonaId: anyPersona._id,
367
+ personaName: `Universal Memory Test`,
368
+ currentSystemPrompt: anyPersona.systemPrompt || 'Universal memory test persona',
369
+ evolutionVersion: 0,
370
+ messagesSinceLastEvolution: 0,
371
+ lastEvolutionDate: new Date(),
372
+ claimedAt: new Date(),
373
+ isActive: true
374
+ });
375
+
376
+ await userPersona.save();
377
+ console.log(`āœ… Created Universal UserPersona: ${userPersona._id}`);
378
+ } else {
379
+ console.log(`āœ… Universal UserPersona already exists: ${userPersona._id}`);
380
+ }
381
+
382
+ return {
383
+ userPersonaId: userPersona._id!.toString(),
384
+ basePersonaId: anyPersona._id!.toString()
385
+ };
386
+
387
+ } catch (error) {
388
+ console.error(`āŒ Failed to setup personas: ${(error as Error).message}`);
389
+ return null;
390
+ }
391
+ }
392
+
393
+ async function testPersonaMemoryInteraction(
394
+ personaKey: string,
395
+ chromaService: ChromaDBService,
396
+ userMongoId: string,
397
+ userPersonaId: string,
398
+ basePersonaId: string
399
+ ) {
400
+ console.log(`\nšŸŽ­ Testing ${PERSONA_CONFIGS[personaKey].name} with Universal Memory System`);
401
+ console.log('=' .repeat(60));
402
+
403
+ const ai = AIModelFactory.createOllamaChatModel('qwen3:8b');
404
+ const memoryTools = createUniversalMemoryTools(chromaService, userMongoId, userPersonaId, basePersonaId);
405
+ ai.registerTools(memoryTools);
406
+ await ai.ensureReady();
407
+
408
+ const systemPrompt = createPersonaSystemPrompt(personaKey);
409
+
410
+ const conversation: LLMChatMessage[] = [
411
+ { role: 'system', content: systemPrompt }
412
+ ];
413
+
414
+ // Test 1: Initial personality expression and memory storage
415
+ console.log(`\nšŸ’¬ ${PERSONA_CONFIGS[personaKey].name} - Initial Conversation`);
416
+ conversation.push({
417
+ role: 'user',
418
+ content: "Hi! I'm Sam, a travel photographer. I love capturing cultural moments and authentic stories during my journeys. I've been feeling a bit stuck creatively lately and could use some inspiration."
419
+ });
420
+
421
+ const response1 = await ai.chatWithTools(conversation, {
422
+ maxToolExecutionRounds: 3
423
+ });
424
+ console.log(`šŸ’ ${PERSONA_CONFIGS[personaKey].name}:`, response1.content);
425
+
426
+ // Test 2: Multiple tool calls for comprehensive recall
427
+ console.log(`\nšŸ’¬ ${PERSONA_CONFIGS[personaKey].name} - Multiple Tool Calls Test`);
428
+
429
+ const freshConversation: LLMChatMessage[] = [
430
+ { role: 'system', content: systemPrompt }
431
+ ];
432
+
433
+ freshConversation.push({
434
+ role: 'user',
435
+ content: "Can you help me plan a creative project based on everything you know about me? I want something that aligns with my interests and addresses my current challenges."
436
+ });
437
+
438
+ const response2 = await ai.chatWithTools(freshConversation, {
439
+ maxToolExecutionRounds: 2 // Should make multiple recalls in first round
440
+ });
441
+ console.log(`šŸ’ ${PERSONA_CONFIGS[personaKey].name}:`, response2.content);
442
+
443
+ ai.dispose();
444
+ console.log(`āœ… ${PERSONA_CONFIGS[personaKey].name} test completed\n`);
445
+ }
446
+
447
+ async function universalMemoryDemo() {
448
+ console.log('🌟 Universal Memory System Demo\n');
449
+ console.log('Testing modular memory system with different personas\n');
450
+
451
+ // Setup database connections
452
+ console.log('šŸ”— Connecting to services...');
453
+ const dbConnection = DatabaseConnection.getInstance();
454
+ await dbConnection.connect();
455
+
456
+ const chromaService = new ChromaDBService();
457
+ await chromaService.initialize();
458
+ console.log('āœ… Services connected\n');
459
+
460
+ // Setup test user
461
+ console.log('šŸ‘¤ Setting up universal demo user...');
462
+ const userId = `universal_demo_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
463
+ await createTestUser(userId);
464
+
465
+ const user = await UserModel.findOne({ userId });
466
+ if (!user || !user._id) throw new Error('User not found after creation');
467
+
468
+ const userMongoId = user._id.toString();
469
+ console.log(`āœ… Demo user created: Sam (${userMongoId})\n`);
470
+
471
+ // Setup personas
472
+ const personaSetup = await setupUniversalPersonas(userId, userMongoId);
473
+ if (!personaSetup) {
474
+ throw new Error('Failed to setup personas');
475
+ }
476
+
477
+ const { userPersonaId, basePersonaId } = personaSetup;
478
+
479
+ try {
480
+ // Test different personas with the same memory system
481
+ const personasToTest = ['astrid', 'maya', 'sophia', 'luna'];
482
+
483
+ console.log('šŸŽ­ Available Personas:');
484
+ personasToTest.forEach(key => {
485
+ const config = PERSONA_CONFIGS[key];
486
+ console.log(` ${config.name}: ${config.personalityPrompt}`);
487
+ });
488
+
489
+ for (const personaKey of personasToTest) {
490
+ await testPersonaMemoryInteraction(
491
+ personaKey,
492
+ chromaService,
493
+ userMongoId,
494
+ userPersonaId,
495
+ basePersonaId
496
+ );
497
+ }
498
+
499
+ // Memory Analysis
500
+ console.log('\n🧠 === Universal Memory Analysis ===');
501
+ const allMemories = await chromaService.getUserInsightsByCategory(
502
+ userMongoId,
503
+ undefined,
504
+ userPersonaId
505
+ );
506
+
507
+ console.log(`šŸ“Š Total memories stored across all personas: ${allMemories.length}`);
508
+
509
+ if (allMemories.length > 0) {
510
+ console.log('\nšŸ’¾ Stored Memories:');
511
+ allMemories.forEach((memory, index) => {
512
+ const metadata = memory.metadata || {};
513
+ console.log(`${index + 1}. [${metadata.category?.toUpperCase() || 'UNKNOWN'}] ${memory.content}`);
514
+ console.log(` šŸ’ Emotional Context: ${metadata.emotionalContext || 'N/A'}`);
515
+ console.log(` šŸ“… Stored: ${metadata.extractedAt || 'N/A'}\n`);
516
+ });
517
+ }
518
+
519
+ console.log('\nšŸŽÆ Universal Memory System Validation:');
520
+ console.log(' āœ… Modular persona separation successful');
521
+ console.log(' āœ… Universal memory instructions work across personas');
522
+ console.log(' āœ… Multiple tool calls in single response optimized');
523
+ console.log(' āœ… Memory persistence across different personality styles');
524
+ console.log(' āœ… Computational efficiency through parallel tool calls');
525
+
526
+ } catch (error) {
527
+ console.error('āŒ Demo error:', (error as Error).message);
528
+ } finally {
529
+ // Clean up test data
530
+ try {
531
+ await UserPersonaModel.deleteMany({ userId: userMongoId });
532
+ await UserModel.deleteOne({ userId });
533
+ console.log(`šŸ—‘ļø Cleaned up demo data for user: ${userId}`);
534
+ } catch (cleanupError) {
535
+ console.warn(`āš ļø Failed to clean up demo data: ${(cleanupError as Error).message}`);
536
+ }
537
+
538
+ console.log('\n🌟 Universal Memory System demo completed!');
539
+ }
540
+ }
541
+
542
+ // Run the demo
543
+ if (require.main === module) {
544
+ universalMemoryDemo()
545
+ .then(() => {
546
+ console.log('šŸŽ‰ Universal Memory Demo completed successfully!');
547
+ process.exit(0);
548
+ })
549
+ .catch((error) => {
550
+ console.error('āŒ Demo failed:', error);
551
+ process.exit(1);
552
+ });
553
+ }
554
+
555
+ export {
556
+ UNIVERSAL_MEMORY_INSTRUCTIONS,
557
+ PERSONA_CONFIGS,
558
+ createPersonaSystemPrompt,
559
+ createUniversalMemoryTools
560
+ };