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,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
|
+
};
|