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.
- package/dist/ai-model.d.ts +20 -22
- package/dist/ai-model.d.ts.map +1 -1
- package/dist/ai-model.js +26 -23
- package/dist/ai-model.js.map +1 -1
- package/dist/client.d.ts +5 -5
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +17 -9
- package/dist/client.js.map +1 -1
- package/dist/http.d.ts +2 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +1 -0
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +49 -11
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js +14 -0
- package/dist/interfaces.js.map +1 -1
- package/dist/providers/anthropic.d.ts +56 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +524 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/google.d.ts +5 -0
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js +64 -8
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +1 -0
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/ollama.d.ts.map +1 -1
- package/dist/providers/ollama.js +38 -11
- package/dist/providers/ollama.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +9 -7
- package/dist/providers/openai.js.map +1 -1
- package/dist/router.d.ts +13 -33
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +33 -57
- package/dist/router.js.map +1 -1
- package/dist/stream-decoder.d.ts +29 -2
- package/dist/stream-decoder.d.ts.map +1 -1
- package/dist/stream-decoder.js +39 -11
- package/dist/stream-decoder.js.map +1 -1
- package/dist/structured-output.d.ts +107 -181
- package/dist/structured-output.d.ts.map +1 -1
- package/dist/structured-output.js +137 -192
- package/dist/structured-output.js.map +1 -1
- package/dist/zod-adapter.d.ts +44 -0
- package/dist/zod-adapter.d.ts.map +1 -0
- package/dist/zod-adapter.js +61 -0
- package/dist/zod-adapter.js.map +1 -0
- package/package.json +9 -1
- package/src/ai-model.ts +350 -0
- package/src/auditor.ts +213 -0
- package/src/client.ts +402 -0
- package/src/debug/debug-google-streaming.ts +97 -0
- package/src/debug/debug-tool-execution.ts +86 -0
- package/src/debug/test-lmstudio-tools.ts +155 -0
- package/src/demos/README.md +47 -0
- package/src/demos/basic/universal-llm-examples.ts +161 -0
- package/src/demos/mcp/astrid-memory-demo.ts +295 -0
- package/src/demos/mcp/astrid-persona-memory.ts +357 -0
- package/src/demos/mcp/mcp-mongodb-demo.ts +275 -0
- package/src/demos/mcp/simple-astrid-memory.ts +148 -0
- package/src/demos/mcp/simple-mcp-demo.ts +68 -0
- package/src/demos/mcp/working-mcp-demo.ts +62 -0
- package/src/demos/model-alias-demo.ts +0 -0
- package/src/demos/tools/RAG_MEMORY_INTEGRATION.md +267 -0
- package/src/demos/tools/astrid-memory-demo.ts +270 -0
- package/src/demos/tools/astrid-production-memory-clean.ts +785 -0
- package/src/demos/tools/astrid-production-memory.ts +558 -0
- package/src/demos/tools/basic-translation-test.ts +66 -0
- package/src/demos/tools/chromadb-similarity-tuning.ts +390 -0
- package/src/demos/tools/clean-multilingual-conversation.ts +209 -0
- package/src/demos/tools/clean-translation-test.ts +119 -0
- package/src/demos/tools/clean-universal-multilingual-test.ts +131 -0
- package/src/demos/tools/complete-rag-demo.ts +369 -0
- package/src/demos/tools/complete-tool-demo.ts +132 -0
- package/src/demos/tools/demo-tool-calling.ts +124 -0
- package/src/demos/tools/dynamic-language-switching-test.ts +251 -0
- package/src/demos/tools/hybrid-thinking-test.ts +154 -0
- package/src/demos/tools/memory-integration-test.ts +420 -0
- package/src/demos/tools/multilingual-memory-system.ts +802 -0
- package/src/demos/tools/ondemand-translation-demo.ts +655 -0
- package/src/demos/tools/production-tool-demo.ts +245 -0
- package/src/demos/tools/revolutionary-multilingual-test.ts +151 -0
- package/src/demos/tools/rigorous-language-analysis.ts +218 -0
- package/src/demos/tools/test-universal-memory-system.ts +126 -0
- package/src/demos/tools/translation-integration-guide.ts +346 -0
- package/src/demos/tools/universal-memory-system.ts +560 -0
- package/src/http.ts +247 -0
- package/src/index.ts +161 -0
- package/src/interfaces.ts +657 -0
- package/src/mcp.ts +345 -0
- package/src/providers/anthropic.ts +762 -0
- package/src/providers/google.ts +620 -0
- package/src/providers/index.ts +8 -0
- package/src/providers/ollama.ts +469 -0
- package/src/providers/openai.ts +392 -0
- package/src/router.ts +780 -0
- package/src/stream-decoder.ts +361 -0
- package/src/structured-output.ts +759 -0
- package/src/test-scripts/test-advanced-tools.ts +310 -0
- package/src/test-scripts/test-google-streaming-enhanced.ts +147 -0
- package/src/test-scripts/test-google-streaming.ts +63 -0
- package/src/test-scripts/test-google-system-prompt-comprehensive.ts +189 -0
- package/src/test-scripts/test-mcp-config.ts +28 -0
- package/src/test-scripts/test-mcp-connection.ts +29 -0
- package/src/test-scripts/test-system-message-positions.ts +163 -0
- package/src/test-scripts/test-system-prompt-improvement-demo.ts +83 -0
- package/src/test-scripts/test-tool-calling.ts +231 -0
- package/src/tests/ai-model.test.ts +1614 -0
- package/src/tests/auditor.test.ts +224 -0
- package/src/tests/http.test.ts +200 -0
- package/src/tests/interfaces.test.ts +117 -0
- package/src/tests/providers/google.test.ts +660 -0
- package/src/tests/providers/ollama.test.ts +954 -0
- package/src/tests/providers/openai.test.ts +1122 -0
- package/src/tests/router.test.ts +254 -0
- package/src/tests/stream-decoder.test.ts +179 -0
- package/src/tests/structured-output.test.ts +1450 -0
- package/src/tests/tools.test.ts +175 -0
- package/src/tools.ts +246 -0
- 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);
|