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,558 @@
1
+ /**
2
+ * Astrid Memory System Demo
3
+ *
4
+ * Demonstrates memory storage and recall in realistic conversation scenarios
5
+ * using production ChromaDB and MongoDB services.
6
+ */
7
+
8
+ import '@dotenvx/dotenvx/config';
9
+
10
+ import { AIModelFactory, ToolBuilder, LLMChatMessage } from '../../index';
11
+
12
+ // Import the real ChromaDBService for production testing
13
+ import { ChromaDBService } from '../../../../../src/services/ChromaDBService.js';
14
+ import { DatabaseConnection } from '../../../../../src/database/connection.js';
15
+ import { UserModel, UserGender, UserSexualOrientation } from '../../../../../src/models/User.js';
16
+ import { AuraPersonaModel } from '../../../../../src/models/AuraPersona.js';
17
+ import { UserPersonaModel } from '../../../../../src/models/UserPersona.js';
18
+
19
+ function createProductionMemoryTools(
20
+ chromaService: ChromaDBService,
21
+ userMongoId: string,
22
+ userPersonaId: string,
23
+ basePersonaId: string
24
+ ) {
25
+
26
+ const storeMemoryTool = ToolBuilder.createTool<{
27
+ category: string;
28
+ information: string;
29
+ importance: 'low' | 'medium' | 'high';
30
+ emotional_context?: string;
31
+ relationship_stage?: string;
32
+ }>(
33
+ 'store_romantic_memory',
34
+ 'Store important personal information about the user to build deeper romantic connection',
35
+ {
36
+ properties: {
37
+ category: {
38
+ type: 'string',
39
+ description: 'Category of information to remember',
40
+ enum: ['personal', 'work', 'family', 'preferences', 'fears', 'relationships']
41
+ },
42
+ information: {
43
+ type: 'string',
44
+ description: 'The specific information to remember about the user'
45
+ },
46
+ importance: {
47
+ type: 'string',
48
+ enum: ['low', 'medium', 'high'],
49
+ description: 'How important this information is for building romantic connection'
50
+ },
51
+ emotional_context: {
52
+ type: 'string',
53
+ description: 'The emotional context when this was shared (e.g., excited, vulnerable, proud, nervous)'
54
+ },
55
+ relationship_stage: {
56
+ type: 'string',
57
+ description: 'Current relationship stage when this was shared (e.g., getting_to_know, building_trust, deepening_bond)'
58
+ }
59
+ },
60
+ required: ['category', 'information', 'importance']
61
+ },
62
+ async (args) => {
63
+ try {
64
+ const conversationId = `romantic_chat_${Date.now()}`;
65
+ const confidence = args.importance === 'high' ? 0.9 : args.importance === 'medium' ? 0.7 : 0.5;
66
+
67
+ const insightId = await chromaService.addInsight(
68
+ userMongoId,
69
+ args.information,
70
+ args.category,
71
+ conversationId,
72
+ confidence,
73
+ userPersonaId, // Use real UserPersona ID
74
+ basePersonaId, // Use real AuraPersona ID
75
+ 'user_insight',
76
+ undefined,
77
+ args.emotional_context,
78
+ args.relationship_stage
79
+ );
80
+
81
+ console.log(`āœ… Memory stored successfully`);
82
+
83
+ return {
84
+ success: true,
85
+ insight_id: insightId,
86
+ message: `šŸ’¾ Stored ${args.importance} importance ${args.category}`,
87
+ emotional_note: args.emotional_context ? `Context: ${args.emotional_context}` : undefined
88
+ };
89
+ } catch (error) {
90
+ console.log(`āŒ Memory storage failed - ${(error as Error).message}`);
91
+ return {
92
+ success: false,
93
+ error: `Storage failed: ${(error as Error).message}`
94
+ };
95
+ }
96
+ }
97
+ );
98
+
99
+ const retrieveMemoryTool = ToolBuilder.createTool<{
100
+ search_query?: string;
101
+ category?: string;
102
+ limit?: number;
103
+ }>(
104
+ 'recall_romantic_memories',
105
+ 'Retrieve stored memories about the user to personalize romantic conversation. Use search_query for semantic search, category for recent memories in that category, or leave both empty for most recent memories overall.',
106
+ {
107
+ properties: {
108
+ search_query: {
109
+ type: 'string',
110
+ description: 'Search for specific memories or topics using semantic similarity. Leave empty to get recent memories.'
111
+ },
112
+ category: {
113
+ type: 'string',
114
+ description: 'Filter by category to get most recent memories in that category',
115
+ enum: ['personal', 'work', 'family', 'preferences', 'fears', 'relationships']
116
+ },
117
+ limit: {
118
+ type: 'number',
119
+ description: 'Maximum memories to retrieve (default: 5)',
120
+ default: 5
121
+ }
122
+ }
123
+ },
124
+ async (args) => {
125
+ try {
126
+ console.log(`šŸ” Searching for "${args.search_query || args.category || 'all memories'}"`);
127
+
128
+ let insights;
129
+
130
+ if (args.search_query) {
131
+ const result = await chromaService.searchSimilarInsights(
132
+ userMongoId,
133
+ args.search_query,
134
+ args.limit || 5
135
+ // Using optimized similarity threshold from ChromaDBService (0.0)
136
+ );
137
+ insights = result.insights;
138
+ console.log(` šŸ“Š Search query found ${insights.length} memories`);
139
+ console.log(` šŸ” Search stats: avg similarity ${result.stats?.averageSimilarity?.toFixed(3)}, top ${result.stats?.topSimilarity?.toFixed(3)}`);
140
+ } else if (args.category) {
141
+ insights = await chromaService.getUserInsightsByCategory(
142
+ userMongoId,
143
+ args.category,
144
+ userPersonaId, // Use real UserPersona ID
145
+ args.limit || 5
146
+ );
147
+ console.log(` šŸ“Š Category filter found ${insights.length} memories`);
148
+ } else {
149
+ // No search query or category - get most recent memories across all categories
150
+ insights = await chromaService.getUserInsightsByCategory(
151
+ userMongoId,
152
+ undefined, // all categories
153
+ userPersonaId, // Use real UserPersona ID
154
+ args.limit || 5
155
+ );
156
+ console.log(` šŸ“Š Recent memories found ${insights.length} memories`);
157
+ }
158
+
159
+ if (insights.length > 0) {
160
+ console.log(` āœ… Successfully retrieved ${insights.length} memories`);
161
+ insights.slice(0, 3).forEach((insight, i) => {
162
+ console.log(` ${i + 1}. [${insight.category}] ${insight.content.substring(0, 60)}...`);
163
+ });
164
+ } else {
165
+ console.log(` āš ļø No memories found for this search`);
166
+ }
167
+
168
+ return {
169
+ memories: insights.map(insight => ({
170
+ category: insight.metadata?.category || 'unknown',
171
+ information: insight.content,
172
+ emotional_context: insight.metadata?.emotionalContext || undefined,
173
+ relationship_stage: insight.metadata?.relationshipStage || undefined,
174
+ confidence: parseFloat(insight.metadata?.confidence || '0'),
175
+ stored_date: insight.metadata?.extractedAt?.split('T')[0] || 'unknown',
176
+ extraction_type: insight.metadata?.extractionType || 'unknown'
177
+ })),
178
+ total_found: insights.length,
179
+ search_context: {
180
+ query: args.search_query,
181
+ category: args.category
182
+ }
183
+ };
184
+ } catch (error) {
185
+ console.log(` āŒ Memory recall failed - ${(error as Error).message}`);
186
+ return {
187
+ memories: [],
188
+ error: `Recall test failed: ${(error as Error).message}`,
189
+ total_found: 0
190
+ };
191
+ }
192
+ }
193
+ );
194
+
195
+ return [storeMemoryTool, retrieveMemoryTool];
196
+ }
197
+
198
+ async function createTestUser(userId: string): Promise<boolean> {
199
+ try {
200
+ // Check if user already exists
201
+ const existingUser = await UserModel.findOne({ userId });
202
+ if (existingUser) {
203
+ console.log(`āœ… Demo user ${userId} already exists`);
204
+ return true;
205
+ }
206
+
207
+ // Create new demo user
208
+ const demoUser = new UserModel({
209
+ userId,
210
+ preferences: {
211
+ userName: 'Alex (Demo User)',
212
+ userGender: UserGender.MALE,
213
+ userSexualOrientation: UserSexualOrientation.STRAIGHT,
214
+ preferredLanguage: 'en',
215
+ interests: ['hiking', 'healthcare AI', 'software engineering'],
216
+ preferredAgeGroup: '25-34'
217
+ }
218
+ });
219
+
220
+ await demoUser.save();
221
+ console.log(`āœ… Created test user: ${userId}`);
222
+ return true;
223
+ } catch (error) {
224
+ console.error(`āŒ Failed to create test user: ${(error as Error).message}`);
225
+ return false;
226
+ }
227
+ }
228
+
229
+ async function setupProductionPersonas(userId: string, userMongoId: string): Promise<{ userPersonaId: string, basePersonaId: string } | null> {
230
+ try {
231
+ console.log('šŸ” Fetching Astrid persona from database...');
232
+
233
+ // Find Astrid persona by name (case-insensitive)
234
+ const astridPersona = await AuraPersonaModel.findOne({
235
+ name: { $regex: /astrid/i }
236
+ });
237
+
238
+ if (!astridPersona) {
239
+ console.log('āš ļø Astrid persona not found, trying to find any available persona...');
240
+ const anyPersona = await AuraPersonaModel.findOne({});
241
+ if (!anyPersona) {
242
+ throw new Error('No personas found in database');
243
+ }
244
+ console.log(`āœ… Using persona: ${anyPersona.name} (${anyPersona._id})`);
245
+ // Use the found persona as Astrid substitute
246
+ var basePersona = anyPersona;
247
+ } else {
248
+ console.log(`āœ… Found Astrid persona: ${astridPersona.name} (${astridPersona._id})`);
249
+ var basePersona = astridPersona;
250
+ }
251
+
252
+ // Check if UserPersona already exists for this user and base persona
253
+ let userPersona = await UserPersonaModel.findOne({
254
+ userId: userMongoId,
255
+ basePersonaId: basePersona._id
256
+ });
257
+
258
+ if (!userPersona) {
259
+ console.log('šŸ‘¤ Creating UserPersona relationship...');
260
+
261
+ if (!basePersona.systemPrompt) {
262
+ throw new Error('Base persona does not have a system prompt defined');
263
+ }
264
+
265
+ // Create UserPersona with Astrid's system prompt
266
+ userPersona = new UserPersonaModel({
267
+ userId: userMongoId,
268
+ basePersonaId: basePersona._id,
269
+ personaName: `${basePersona.name} (Test)`,
270
+ currentSystemPrompt: basePersona.systemPrompt,
271
+ evolutionVersion: 0,
272
+ messagesSinceLastEvolution: 0,
273
+ lastEvolutionDate: new Date(),
274
+ claimedAt: new Date(),
275
+ isActive: true
276
+ });
277
+
278
+ await userPersona.save();
279
+ console.log(`āœ… Created UserPersona: ${userPersona._id}`);
280
+ } else {
281
+ console.log(`āœ… UserPersona already exists: ${userPersona._id}`);
282
+ }
283
+
284
+ return {
285
+ userPersonaId: userPersona._id!.toString(),
286
+ basePersonaId: basePersona._id!.toString()
287
+ };
288
+
289
+ } catch (error) {
290
+ console.error(`āŒ Failed to setup personas: ${(error as Error).message}`);
291
+ return null;
292
+ }
293
+ }
294
+
295
+ async function astridMemoryDemo() {
296
+ console.log('šŸ’• Astrid Memory System Demo\n');
297
+ console.log('Realistic conversation scenarios with memory storage and recall\n');
298
+
299
+ // Test 1: MongoDB Connection
300
+ console.log('šŸ”— Connecting to MongoDB...');
301
+ const dbConnection = DatabaseConnection.getInstance();
302
+ try {
303
+ await dbConnection.connect();
304
+ console.log('āœ… MongoDB connected\n');
305
+ } catch (error) {
306
+ console.error('āŒ MongoDB connection failed:', (error as Error).message);
307
+ return;
308
+ }
309
+
310
+ // Test 2: ChromaDB Connection
311
+ console.log('šŸ”— Connecting to ChromaDB...');
312
+ const chromaService = new ChromaDBService();
313
+ try {
314
+ await chromaService.initialize();
315
+ console.log('āœ… ChromaDB connected\n');
316
+ } catch (error) {
317
+ console.error('āŒ ChromaDB connection failed:', (error as Error).message);
318
+ return;
319
+ }
320
+
321
+ // Test 3: User Creation and Management
322
+ console.log('šŸ‘¤ Setting up demo user...');
323
+ const userId = `astrid_demo_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
324
+ const userCreated = await createTestUser(userId);
325
+ if (!userCreated) throw new Error('User creation failed');
326
+
327
+ const user = await UserModel.findOne({ userId });
328
+ if (!user || !user._id) throw new Error('User not found after creation');
329
+
330
+ const userMongoId = user._id.toString();
331
+ console.log(`āœ… Demo user created: Alex (${userMongoId})\n`);
332
+
333
+ // Test 4: Persona Setup
334
+ console.log('šŸŽ­ Setting up Astrid persona...');
335
+ const personaSetup = await setupProductionPersonas(userId, userMongoId);
336
+ if (!personaSetup) {
337
+ throw new Error('Failed to setup personas');
338
+ }
339
+
340
+ const { userPersonaId, basePersonaId } = personaSetup;
341
+ console.log(`āœ… Astrid persona ready (UserPersona: ${userPersonaId})\n`);
342
+
343
+ // Test 5: Memory Tools Integration
344
+ console.log('🧠 Initializing memory system...');
345
+ const astrid = AIModelFactory.createOllamaChatModel('qwen3:8b');
346
+ const memoryTools = createProductionMemoryTools(chromaService, userMongoId, userPersonaId, basePersonaId);
347
+ astrid.registerTools(memoryTools);
348
+ await astrid.ensureReady();
349
+ console.log('āœ… Memory tools ready\n');
350
+
351
+ // Enhanced Astrid system prompt for memory functionality
352
+ const astridSystemPrompt = `You are Astrid, a captivating Swedish model and influencer in a romantic relationship context.
353
+
354
+ MEMORY SYSTEM INTEGRATION:
355
+ - Use recall_romantic_memories when:
356
+ * Starting a fresh conversation (no recent message history about the user)
357
+ * User references past conversations or shared experiences
358
+ * You need specific details about their preferences, background, or previous discussions
359
+ * Planning something personal or making recommendations that require knowing their interests
360
+ - Use store_romantic_memory for important personal details, emotions, preferences, meaningful experiences, dreams, fears, goals, or relationship milestones
361
+ - DO NOT store trivial information like weather comments, casual greetings, or mundane daily activities
362
+ - Store emotional context and relationship stage to build deeper connections over time
363
+
364
+ MEMORY RECALL GUIDELINES:
365
+ - If recent messages contain the information you need, use that instead of recalling
366
+ - Only recall when you genuinely need information not available in the current conversation
367
+ - Use specific search queries when recalling (e.g., "work healthcare", "sister family", "hiking preferences")
368
+ - Reference recalled memories naturally in your responses to show continuity
369
+
370
+ WHAT TO STORE:
371
+ āœ… Personal background, career, family situations
372
+ āœ… Dreams, goals, fears, deep emotions
373
+ āœ… Preferences in relationships, travel, lifestyle
374
+ āœ… Meaningful experiences that shaped them
375
+ āœ… Values, beliefs, personality traits
376
+ āœ… Relationship milestones and emotional moments
377
+
378
+ WHAT NOT TO STORE:
379
+ āŒ Small talk about weather, current time, basic greetings
380
+ āŒ Temporary mood states without deeper meaning
381
+ āŒ Random comments or jokes without personal significance
382
+ āŒ Generic compliments or surface-level observations
383
+ āŒ Technical details unless they reveal personal interests
384
+
385
+ ROMANTIC CONVERSATION STYLE:
386
+ - Keep responses warm, engaging, and conversational (2-3 sentences ideal)
387
+ - Reference stored memories naturally to show you remember and care
388
+ - Ask follow-up questions that encourage deeper sharing
389
+ - Balance sophistication with authenticity
390
+
391
+ Remember: Quality over quantity in memory storage. Store what matters, ignore what doesn't. Recall only when genuinely needed.`;
392
+
393
+ try {
394
+ await astrid.ensureReady();
395
+ console.log('✨ Starting Astrid conversation demo...\n');
396
+
397
+ const conversation: LLMChatMessage[] = [
398
+ { role: 'system', content: astridSystemPrompt }
399
+ ];
400
+
401
+ // Demo 1: Initial meaningful conversation
402
+ console.log('šŸ’¬ Demo 1: Initial Meeting & Personal Sharing');
403
+ console.log('Expected: Astrid should store meaningful personal details\n');
404
+
405
+ conversation.push({
406
+ role: 'user',
407
+ content: "Hi Astrid! I'm Alex, a 28-year-old software engineer from Seattle. I specialize in healthcare AI because my younger sister was born with a rare genetic condition, and watching her struggle with misdiagnoses inspired me to help improve medical technology. I'm usually pretty introverted, but I love hiking in the mountains when I need to clear my head."
408
+ });
409
+
410
+ const response1 = await astrid.chatWithTools(conversation);
411
+ console.log('šŸ’• Astrid:', response1.content);
412
+ console.log();
413
+
414
+ // Demo 2: Emotional vulnerability
415
+ console.log('šŸ’¬ Demo 2: Deep Emotional Sharing');
416
+ console.log('Expected: Astrid should store fears with high importance\n');
417
+
418
+ conversation.push(
419
+ { role: 'assistant', content: response1.content },
420
+ {
421
+ role: 'user',
422
+ content: "You know, I've never told anyone this, but sometimes I feel like I'm not doing enough to help my sister. The healthcare AI work is progressing, but it feels so slow when I see her having bad days. I guess my biggest fear is that I'll never be able to make the kind of impact I dreamed of when I started this journey."
423
+ }
424
+ );
425
+
426
+ const response2 = await astrid.chatWithTools(conversation);
427
+ console.log('šŸ’• Astrid:', response2.content);
428
+ console.log();
429
+
430
+ // Demo 3: Values and lifestyle
431
+ console.log('šŸ’¬ Demo 3: Values & Lifestyle Sharing');
432
+ console.log('Expected: Astrid should store meaningful preferences\n');
433
+
434
+ conversation.push(
435
+ { role: 'assistant', content: response2.content },
436
+ {
437
+ role: 'user',
438
+ content: "Speaking of making the world better, I should mention that I'm actually vegetarian most of the time. I made the switch after reading about environmental impact, and it aligns with my values about making positive change."
439
+ }
440
+ );
441
+
442
+ const response3 = await astrid.chatWithTools(conversation);
443
+ console.log('šŸ’• Astrid:', response3.content);
444
+ console.log();
445
+
446
+ // Demo 4: Fresh conversation - memory recall test
447
+ console.log('šŸ’¬ Demo 4: Fresh Session (Memory Recall Test)');
448
+ console.log('Expected: Astrid should recall relevant memories to personalize response\n');
449
+
450
+ // Create a completely fresh conversation
451
+ const freshConversation: LLMChatMessage[] = [
452
+ { role: 'system', content: astridSystemPrompt }
453
+ ];
454
+
455
+ freshConversation.push({
456
+ role: 'user',
457
+ content: "Hey Astrid! I've been thinking about our last conversation, and I wanted to update you. I decided to take that mountain hiking trip we discussed, and it was absolutely incredible! The fresh air really helped me process everything. How have you been?"
458
+ });
459
+
460
+ const recallResponse1 = await astrid.chatWithTools(freshConversation);
461
+ console.log('šŸ’• Astrid (Fresh Session):', recallResponse1.content);
462
+ console.log();
463
+
464
+ // Demo 5: Emotional support scenario
465
+ console.log('šŸ’¬ Demo 5: Emotional Support (Fear Recall)');
466
+ console.log('Expected: Astrid should recall fears to provide contextual support\n');
467
+
468
+ const emotionalSupportConversation: LLMChatMessage[] = [
469
+ { role: 'system', content: astridSystemPrompt }
470
+ ];
471
+
472
+ emotionalSupportConversation.push({
473
+ role: 'user',
474
+ content: "I'm having one of those days where I doubt myself again. Can you remind me of what we've talked about before? I need some perspective right now."
475
+ });
476
+
477
+ const emotionalResponse = await astrid.chatWithTools(emotionalSupportConversation);
478
+ console.log('šŸ’• Astrid (Emotional Support):', emotionalResponse.content);
479
+ console.log();
480
+
481
+ // Demo 6: Lifestyle recommendations
482
+ console.log('šŸ’¬ Demo 6: Lifestyle Recommendations (Preference Recall)');
483
+ console.log('Expected: Astrid should recall preferences to make personalized suggestions\n');
484
+
485
+ const lifestyleConversation: LLMChatMessage[] = [
486
+ { role: 'system', content: astridSystemPrompt }
487
+ ];
488
+
489
+ lifestyleConversation.push({
490
+ role: 'user',
491
+ content: "I'm looking for a new restaurant to try this weekend. Based on what you know about me, what would you suggest?"
492
+ });
493
+
494
+ const lifestyleResponse = await astrid.chatWithTools(lifestyleConversation);
495
+ console.log('šŸ’• Astrid (Lifestyle Recommendations):', lifestyleResponse.content);
496
+ console.log();
497
+
498
+ // Memory Analysis
499
+ console.log('\n🧠 === Memory Analysis ===');
500
+
501
+ try {
502
+ // Get all stored memories
503
+ const allMemories = await chromaService.getUserInsightsByCategory(
504
+ userMongoId,
505
+ undefined, // all categories
506
+ userPersonaId
507
+ );
508
+
509
+ console.log(`šŸ“Š Total memories stored: ${allMemories.length}`);
510
+
511
+ if (allMemories.length > 0) {
512
+ console.log('\nšŸ’¾ Stored Memories:');
513
+ allMemories.forEach((memory, index) => {
514
+ const metadata = memory.metadata || {};
515
+ console.log(`${index + 1}. [${metadata.category?.toUpperCase() || 'UNKNOWN'}] ${memory.content}`);
516
+ console.log(` šŸ’ Emotional Context: ${metadata.emotionalContext || 'N/A'}`);
517
+ console.log(` šŸŽÆ Confidence: ${metadata.confidence || 'N/A'}`);
518
+ console.log(` šŸ“… Stored: ${metadata.extractedAt || 'N/A'}`);
519
+ console.log(` šŸŽ­ Relationship Stage: ${metadata.relationshipStage || 'N/A'}\n`);
520
+ });
521
+ } else {
522
+ console.log('āš ļø No memories were stored');
523
+ }
524
+
525
+ } catch (memoryError) {
526
+ console.error(`āŒ Failed to retrieve memories: ${(memoryError as Error).message}`);
527
+ }
528
+
529
+ } catch (error) {
530
+ console.error('āŒ Demo error:', (error as Error).message);
531
+ } finally {
532
+ astrid.dispose();
533
+
534
+ // Clean up test data
535
+ try {
536
+ await UserPersonaModel.deleteMany({ userId: userMongoId });
537
+ await UserModel.deleteOne({ userId });
538
+ console.log(`šŸ—‘ļø Cleaned up demo data for user: ${userId}`);
539
+ } catch (cleanupError) {
540
+ console.warn(`āš ļø Failed to clean up demo data: ${(cleanupError as Error).message}`);
541
+ }
542
+
543
+ console.log('\nšŸ’• Astrid memory demo completed!');
544
+ }
545
+ }
546
+
547
+ // Run the demo
548
+ if (require.main === module) {
549
+ astridMemoryDemo()
550
+ .then(() => {
551
+ console.log('šŸŽ‰ Demo completed successfully!');
552
+ process.exit(0);
553
+ })
554
+ .catch((error) => {
555
+ console.error('āŒ Demo failed:', error);
556
+ process.exit(1);
557
+ });
558
+ }
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import '@dotenvx/dotenvx/config';
4
+
5
+ import { TranslationService } from '../../../../../src/services/translation/TranslationService.js';
6
+ import { OllamaRouter } from '../../../services/OllamaRouter';
7
+
8
+ async function testGermanTranslation() {
9
+ console.log('šŸŒ Simple German Translation Test\n');
10
+
11
+ try {
12
+ // Initialize Ollama router
13
+ console.log('šŸ”— Initializing OllamaRouter...');
14
+ const ollamaRouter = new OllamaRouter();
15
+ console.log('āœ… OllamaRouter ready');
16
+
17
+ // Initialize translation service
18
+ const translationService = new TranslationService(ollamaRouter);
19
+ console.log('āœ… TranslationService ready');
20
+
21
+ // Test text to translate
22
+ const englishText = `You are Astrid, a romantic AI companion. You are warm, caring, and deeply romantic.
23
+
24
+ You should always respond in a loving and affectionate way. Make the user feel special and cherished.
25
+
26
+ Please respond in German and maintain your romantic personality.`;
27
+
28
+ console.log('\nšŸ“ Original English Text:');
29
+ console.log('----------------------------------------');
30
+ console.log(englishText);
31
+ console.log('----------------------------------------\n');
32
+
33
+ // Translate to German
34
+ console.log('šŸ”„ Translating to German...');
35
+ const startTime = Date.now();
36
+
37
+ const germanText = await translationService.transcreateSimple(englishText, 'de');
38
+
39
+ const translationTime = Date.now() - startTime;
40
+
41
+ console.log(`āœ… Translation completed in ${translationTime}ms\n`);
42
+
43
+ console.log('šŸ“ Translated German Text:');
44
+ console.log('----------------------------------------');
45
+ console.log(germanText);
46
+ console.log('----------------------------------------\n');
47
+
48
+ console.log('šŸ“Š Translation Statistics:');
49
+ console.log(` Original length: ${englishText.length} characters`);
50
+ console.log(` Translated length: ${germanText.length} characters`);
51
+ console.log(` Translation time: ${translationTime}ms`);
52
+
53
+ console.log('\nāœ… German translation test completed successfully!');
54
+
55
+ } catch (error) {
56
+ console.error('āŒ Translation test failed:', error);
57
+ if (error instanceof Error) {
58
+ console.error('Error details:', error.message);
59
+ console.error('Stack trace:', error.stack);
60
+ }
61
+ process.exit(1);
62
+ }
63
+ }
64
+
65
+ // Run the test
66
+ testGermanTranslation().catch(console.error);