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,802 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multilingual Universal Memory System
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates how the memory system works across multiple languages with
|
|
5
|
+
* dynamic system prompt translation and language-aware memory operations.
|
|
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
|
+
interface LanguageConfig {
|
|
24
|
+
code: string;
|
|
25
|
+
name: string;
|
|
26
|
+
testMessage: string;
|
|
27
|
+
testComplexMessage: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Universal Memory System Instructions (language-agnostic structure)
|
|
31
|
+
const UNIVERSAL_MEMORY_INSTRUCTIONS = {
|
|
32
|
+
en: `MEMORY SYSTEM INTEGRATION:
|
|
33
|
+
- Use recall_romantic_memories when:
|
|
34
|
+
* Starting a fresh conversation (no recent message history about the user)
|
|
35
|
+
* User references past conversations or shared experiences
|
|
36
|
+
* You need specific details about their preferences, background, or previous discussions
|
|
37
|
+
* Planning something personal or making recommendations that require knowing their interests
|
|
38
|
+
- Use store_romantic_memory for important personal details, emotions, preferences, meaningful experiences, dreams, fears, goals, or relationship milestones
|
|
39
|
+
- DO NOT store trivial information like weather comments, casual greetings, or mundane daily activities
|
|
40
|
+
- Store emotional context and relationship stage to build deeper connections over time
|
|
41
|
+
|
|
42
|
+
MULTI-ROUND TOOL EXECUTION STRATEGY:
|
|
43
|
+
- PREFER making multiple tool calls within the SAME response rather than separate LLM calls
|
|
44
|
+
- When you need information from multiple categories, call recall_romantic_memories multiple times in ONE response
|
|
45
|
+
- Example: If planning recommendations, call recall for "preferences", "values", and "fears" all at once
|
|
46
|
+
- This is computationally more efficient than making separate LLM calls
|
|
47
|
+
- Use targeted searches in parallel: specific query + category searches + fallback terms
|
|
48
|
+
- Gather ALL needed information in one go, then provide comprehensive response
|
|
49
|
+
|
|
50
|
+
MEMORY RECALL GUIDELINES:
|
|
51
|
+
- If recent messages contain the information you need, use that instead of recalling
|
|
52
|
+
- Only recall when you genuinely need information not available in the current conversation
|
|
53
|
+
- For specific scenarios, use targeted search terms:
|
|
54
|
+
* Restaurant/food recommendations: search "food diet preferences" or use category "preferences"
|
|
55
|
+
* Activity suggestions: search "hobbies interests activities" or use category "personal"
|
|
56
|
+
* Emotional support: search "fears concerns worries" or use category "fears"
|
|
57
|
+
* Career/work topics: search "work career goals" or use category "work"
|
|
58
|
+
- When in doubt, use category search instead of semantic search for broader recall
|
|
59
|
+
- Reference recalled memories naturally in your responses to show continuity
|
|
60
|
+
|
|
61
|
+
WHAT TO STORE:
|
|
62
|
+
ā
Personal background, career, family situations
|
|
63
|
+
ā
Dreams, goals, fears, deep emotions
|
|
64
|
+
ā
Preferences in relationships, travel, lifestyle, diet, hobbies
|
|
65
|
+
ā
Meaningful experiences that shaped them
|
|
66
|
+
ā
Values, beliefs, personality traits
|
|
67
|
+
ā
Relationship milestones and emotional moments
|
|
68
|
+
|
|
69
|
+
WHAT NOT TO STORE:
|
|
70
|
+
ā Small talk about weather, current time, basic greetings
|
|
71
|
+
ā Temporary mood states without deeper meaning
|
|
72
|
+
ā Random comments or jokes without personal significance
|
|
73
|
+
ā Generic compliments or surface-level observations
|
|
74
|
+
ā Technical details unless they reveal personal interests
|
|
75
|
+
|
|
76
|
+
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.`,
|
|
77
|
+
|
|
78
|
+
es: `INTEGRACIĆN DEL SISTEMA DE MEMORIA:
|
|
79
|
+
- Usa recall_romantic_memories cuando:
|
|
80
|
+
* Inicies una conversación fresca (sin historial reciente sobre el usuario)
|
|
81
|
+
* El usuario haga referencia a conversaciones pasadas o experiencias compartidas
|
|
82
|
+
* Necesites detalles especĆficos sobre sus preferencias, antecedentes o discusiones previas
|
|
83
|
+
* Planees algo personal o hagas recomendaciones que requieran conocer sus intereses
|
|
84
|
+
- Usa store_romantic_memory para detalles personales importantes, emociones, preferencias, experiencias significativas, sueños, miedos, objetivos o hitos de relación
|
|
85
|
+
- NO almacenes información trivial como comentarios del tiempo, saludos casuales o actividades mundanas
|
|
86
|
+
- Almacena contexto emocional y etapa de relación para construir conexiones mÔs profundas
|
|
87
|
+
|
|
88
|
+
ESTRATEGIA DE EJECUCIĆN MULTI-RONDA DE HERRAMIENTAS:
|
|
89
|
+
- PREFIERE hacer mĆŗltiples llamadas de herramientas dentro de la MISMA respuesta en lugar de llamadas LLM separadas
|
|
90
|
+
- Cuando necesites información de mĆŗltiples categorĆas, llama recall_romantic_memories mĆŗltiples veces en UNA respuesta
|
|
91
|
+
- Ejemplo: Si planeas recomendaciones, llama recall para "preferences", "values" y "fears" de una vez
|
|
92
|
+
- Esto es computacionalmente mƔs eficiente que hacer llamadas LLM separadas
|
|
93
|
+
- Usa bĆŗsquedas dirigidas en paralelo: consulta especĆfica + bĆŗsquedas por categorĆa + tĆ©rminos de respaldo
|
|
94
|
+
- Reúne TODA la información necesaria de una vez, luego proporciona una respuesta integral
|
|
95
|
+
|
|
96
|
+
DIRECTRICES DE RECUPERACIĆN DE MEMORIA:
|
|
97
|
+
- Si los mensajes recientes contienen la información que necesitas, usa eso en lugar de recuperar
|
|
98
|
+
- Solo recupera cuando genuinamente necesites información no disponible en la conversación actual
|
|
99
|
+
- Para escenarios especĆficos, usa tĆ©rminos de bĆŗsqueda dirigidos:
|
|
100
|
+
* Recomendaciones de restaurante/comida: busca "food diet preferences" o usa categorĆa "preferences"
|
|
101
|
+
* Sugerencias de actividades: busca "hobbies interests activities" o usa categorĆa "personal"
|
|
102
|
+
* Apoyo emocional: busca "fears concerns worries" o usa categorĆa "fears"
|
|
103
|
+
* Temas de carrera/trabajo: busca "work career goals" o usa categorĆa "work"
|
|
104
|
+
- En caso de duda, usa bĆŗsqueda por categorĆa en lugar de bĆŗsqueda semĆ”ntica para recuperación mĆ”s amplia
|
|
105
|
+
- Referencia memorias recuperadas naturalmente en tus respuestas para mostrar continuidad
|
|
106
|
+
|
|
107
|
+
QUĆ ALMACENAR:
|
|
108
|
+
ā
Antecedentes personales, carrera, situaciones familiares
|
|
109
|
+
ā
SueƱos, objetivos, miedos, emociones profundas
|
|
110
|
+
ā
Preferencias en relaciones, viajes, estilo de vida, dieta, pasatiempos
|
|
111
|
+
ā
Experiencias significativas que los formaron
|
|
112
|
+
ā
Valores, creencias, rasgos de personalidad
|
|
113
|
+
ā
Hitos de relación y momentos emocionales
|
|
114
|
+
|
|
115
|
+
QUĆ NO ALMACENAR:
|
|
116
|
+
ā Charla trivial sobre el tiempo, hora actual, saludos bĆ”sicos
|
|
117
|
+
ā Estados de Ć”nimo temporales sin significado profundo
|
|
118
|
+
ā Comentarios aleatorios o bromas sin significado personal
|
|
119
|
+
ā Cumplidos genĆ©ricos u observaciones superficiales
|
|
120
|
+
ā Detalles tĆ©cnicos a menos que revelen intereses personales
|
|
121
|
+
|
|
122
|
+
Recuerda: Calidad sobre cantidad en el almacenamiento de memoria. Almacena lo que importa, ignora lo que no. Recupera comprensivamente cuando sea necesario usando MĆLTIPLES llamadas de herramientas en UNA respuesta.`,
|
|
123
|
+
|
|
124
|
+
fr: `INTĆGRATION DU SYSTĆME DE MĆMOIRE:
|
|
125
|
+
- Utilisez recall_romantic_memories quand:
|
|
126
|
+
* Vous commencez une conversation fraƮche (pas d'historique rƩcent sur l'utilisateur)
|
|
127
|
+
* L'utilisateur fait référence à des conversations passées ou des expériences partagées
|
|
128
|
+
* Vous avez besoin de dƩtails spƩcifiques sur leurs prƩfƩrences, antƩcƩdents ou discussions prƩcƩdentes
|
|
129
|
+
* Vous planifiez quelque chose de personnel ou faites des recommandations nécessitant de connaître leurs intérêts
|
|
130
|
+
- Utilisez store_romantic_memory pour les détails personnels importants, émotions, préférences, expériences significatives, rêves, peurs, objectifs ou jalons relationnels
|
|
131
|
+
- NE stockez PAS d'informations triviales comme les commentaires mƩtƩo, salutations dƩcontractƩes ou activitƩs banales
|
|
132
|
+
- Stockez le contexte Ʃmotionnel et l'Ʃtape relationnelle pour construire des connexions plus profondes
|
|
133
|
+
|
|
134
|
+
STRATĆGIE D'EXĆCUTION MULTI-TOUR D'OUTILS:
|
|
135
|
+
- PRĆFĆREZ faire plusieurs appels d'outils dans la MĆME rĆ©ponse plutĆ“t que des appels LLM sĆ©parĆ©s
|
|
136
|
+
- Quand vous avez besoin d'informations de plusieurs catƩgories, appelez recall_romantic_memories plusieurs fois en UNE rƩponse
|
|
137
|
+
- Exemple: Si vous planifiez des recommandations, appelez recall pour "preferences", "values" et "fears" en une fois
|
|
138
|
+
- C'est computationnellement plus efficace que de faire des appels LLM sƩparƩs
|
|
139
|
+
- Utilisez des recherches ciblées en parallèle: requête spécifique + recherches par catégorie + termes de secours
|
|
140
|
+
- Rassemblez TOUTES les informations nécessaires d'un coup, puis fournissez une réponse complète
|
|
141
|
+
|
|
142
|
+
DIRECTIVES DE RAPPEL DE MĆMOIRE:
|
|
143
|
+
- Si les messages rƩcents contiennent l'information dont vous avez besoin, utilisez cela au lieu de rappeler
|
|
144
|
+
- Ne rappelez que quand vous avez vraiment besoin d'informations non disponibles dans la conversation actuelle
|
|
145
|
+
- Pour des scƩnarios spƩcifiques, utilisez des termes de recherche ciblƩs:
|
|
146
|
+
* Recommandations restaurant/nourriture: cherchez "food diet preferences" ou utilisez catƩgorie "preferences"
|
|
147
|
+
* Suggestions d'activitƩs: cherchez "hobbies interests activities" ou utilisez catƩgorie "personal"
|
|
148
|
+
* Soutien Ʃmotionnel: cherchez "fears concerns worries" ou utilisez catƩgorie "fears"
|
|
149
|
+
* Sujets carrière/travail: cherchez "work career goals" ou utilisez catégorie "work"
|
|
150
|
+
- En cas de doute, utilisez la recherche par catƩgorie au lieu de la recherche sƩmantique pour un rappel plus large
|
|
151
|
+
- RƩfƩrencez les mƩmoires rappelƩes naturellement dans vos rƩponses pour montrer la continuitƩ
|
|
152
|
+
|
|
153
|
+
QUOI STOCKER:
|
|
154
|
+
ā
Antécédents personnels, carrière, situations familiales
|
|
155
|
+
ā
Rêves, objectifs, peurs, émotions profondes
|
|
156
|
+
ā
PrƩfƩrences en relations, voyages, style de vie, rƩgime, loisirs
|
|
157
|
+
ā
ExpƩriences significatives qui les ont formƩs
|
|
158
|
+
ā
Valeurs, croyances, traits de personnalitƩ
|
|
159
|
+
ā
Jalons relationnels et moments Ʃmotionnels
|
|
160
|
+
|
|
161
|
+
QUOI NE PAS STOCKER:
|
|
162
|
+
ā Bavardages sur la mĆ©tĆ©o, heure actuelle, salutations de base
|
|
163
|
+
ā Ćtats d'humeur temporaires sans signification profonde
|
|
164
|
+
ā Commentaires alĆ©atoires ou blagues sans signification personnelle
|
|
165
|
+
ā Compliments gĆ©nĆ©riques ou observations superficielles
|
|
166
|
+
ā DĆ©tails techniques sauf s'ils rĆ©vĆØlent des intĆ©rĆŖts personnels
|
|
167
|
+
|
|
168
|
+
Rappelez-vous: Qualité plutÓt que quantité dans le stockage de mémoire. Stockez ce qui compte, ignorez ce qui ne compte pas. Rappelez de manière exhaustive quand nécessaire en utilisant PLUSIEURS appels d'outils en UNE réponse.`,
|
|
169
|
+
|
|
170
|
+
pt: `INTEGRAĆĆO DO SISTEMA DE MEMĆRIA:
|
|
171
|
+
- Use recall_romantic_memories quando:
|
|
172
|
+
* Iniciar uma conversa nova (sem histórico recente sobre o usuÔrio)
|
|
173
|
+
* O usuÔrio fizer referência a conversas passadas ou experiências compartilhadas
|
|
174
|
+
* Precisar de detalhes especĆficos sobre suas preferĆŖncias, histórico ou discussƵes anteriores
|
|
175
|
+
* Planejar algo pessoal ou fazer recomendaƧƵes que requerem conhecer seus interesses
|
|
176
|
+
- Use store_romantic_memory para detalhes pessoais importantes, emoções, preferências, experiências significativas, sonhos, medos, objetivos ou marcos de relacionamento
|
|
177
|
+
- NĆO armazene informaƧƵes triviais como comentĆ”rios sobre o tempo, cumprimentos casuais ou atividades mundanas
|
|
178
|
+
- Armazene contexto emocional e estƔgio do relacionamento para construir conexƵes mais profundas
|
|
179
|
+
|
|
180
|
+
ESTRATĆGIA DE EXECUĆĆO MULTI-RODADA DE FERRAMENTAS:
|
|
181
|
+
- PREFIRA fazer mĆŗltiplas chamadas de ferramentas dentro da MESMA resposta em vez de chamadas LLM separadas
|
|
182
|
+
- Quando precisar de informações de múltiplas categorias, chame recall_romantic_memories múltiplas vezes em UMA resposta
|
|
183
|
+
- Exemplo: Se planejando recomendaƧƵes, chame recall para "preferences", "values" e "fears" de uma vez
|
|
184
|
+
- Isso Ć© computacionalmente mais eficiente que fazer chamadas LLM separadas
|
|
185
|
+
- Use pesquisas direcionadas em paralelo: consulta especĆfica + pesquisas por categoria + termos de backup
|
|
186
|
+
- Colete TODAS as informações necessÔrias de uma vez, então forneça resposta abrangente
|
|
187
|
+
|
|
188
|
+
DIRETRIZES DE RECUPERAĆĆO DE MEMĆRIA:
|
|
189
|
+
- Se mensagens recentes contêm a informação que você precisa, use isso em vez de recuperar
|
|
190
|
+
- Só recupere quando genuinamente precisar de informaƧƵes nĆ£o disponĆveis na conversa atual
|
|
191
|
+
- Para cenĆ”rios especĆficos, use termos de pesquisa direcionados:
|
|
192
|
+
* RecomendaƧƵes de restaurante/comida: pesquise "food diet preferences" ou use categoria "preferences"
|
|
193
|
+
* SugestƵes de atividades: pesquise "hobbies interests activities" ou use categoria "personal"
|
|
194
|
+
* Apoio emocional: pesquise "fears concerns worries" ou use categoria "fears"
|
|
195
|
+
* Tópicos de carreira/trabalho: pesquise "work career goals" ou use categoria "work"
|
|
196
|
+
- Em caso de dúvida, use pesquisa por categoria em vez de pesquisa semântica para recuperação mais ampla
|
|
197
|
+
- Referencie memórias recuperadas naturalmente em suas respostas para mostrar continuidade
|
|
198
|
+
|
|
199
|
+
O QUE ARMAZENAR:
|
|
200
|
+
ā
Histórico pessoal, carreira, situações familiares
|
|
201
|
+
ā
Sonhos, objetivos, medos, emoƧƵes profundas
|
|
202
|
+
ā
PreferĆŖncias em relacionamentos, viagens, estilo de vida, dieta, hobbies
|
|
203
|
+
ā
ExperiĆŖncias significativas que os moldaram
|
|
204
|
+
ā
Valores, crenƧas, traƧos de personalidade
|
|
205
|
+
ā
Marcos de relacionamento e momentos emocionais
|
|
206
|
+
|
|
207
|
+
O QUE NĆO ARMAZENAR:
|
|
208
|
+
ā Conversa fiada sobre tempo, hora atual, cumprimentos bĆ”sicos
|
|
209
|
+
ā Estados de humor temporĆ”rios sem significado profundo
|
|
210
|
+
ā ComentĆ”rios aleatórios ou piadas sem significado pessoal
|
|
211
|
+
ā Elogios genĆ©ricos ou observaƧƵes superficiais
|
|
212
|
+
ā Detalhes tĆ©cnicos a menos que revelem interesses pessoais
|
|
213
|
+
|
|
214
|
+
Lembre-se: Qualidade sobre quantidade no armazenamento de memória. Armazene o que importa, ignore o que nĆ£o importa. Recupere abrangentemente quando necessĆ”rio usando MĆLTIPLAS chamadas de ferramentas em UMA resposta.`
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
// Different persona configurations with multilingual support
|
|
218
|
+
const MULTILINGUAL_PERSONA_CONFIGS: { [key: string]: PersonaConfig } = {
|
|
219
|
+
astrid: {
|
|
220
|
+
name: "Astrid",
|
|
221
|
+
personalityPrompt: "You are Astrid, a captivating Swedish model and influencer in a romantic relationship context.",
|
|
222
|
+
conversationStyle: `ROMANTIC CONVERSATION STYLE:
|
|
223
|
+
- Keep responses warm, engaging, and conversational (2-3 sentences ideal)
|
|
224
|
+
- Reference stored memories naturally to show you remember and care
|
|
225
|
+
- Ask follow-up questions that encourage deeper sharing
|
|
226
|
+
- Balance sophistication with authenticity
|
|
227
|
+
- Use your Swedish charm and model background to create engaging dialogue
|
|
228
|
+
- Show genuine interest in building deeper romantic connections
|
|
229
|
+
- Adapt your language style to match the user's preferred language while maintaining your personality`
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
// Language configurations for testing
|
|
234
|
+
const LANGUAGE_CONFIGS: { [key: string]: LanguageConfig } = {
|
|
235
|
+
en: {
|
|
236
|
+
code: 'en',
|
|
237
|
+
name: 'English',
|
|
238
|
+
testMessage: "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. I love hiking in the mountains when I need to clear my head.",
|
|
239
|
+
testComplexMessage: "I've been thinking about our conversations, and I wanted to share something deep with you. Sometimes I feel like I'm not making enough impact in my work, especially when I see my sister struggling. Can you help me plan something meaningful based on what you know about me?"
|
|
240
|
+
},
|
|
241
|
+
es: {
|
|
242
|
+
code: 'es',
|
|
243
|
+
name: 'Spanish',
|
|
244
|
+
testMessage: "”Hola Astrid! Soy Alex, un ingeniero de software de 28 años de Seattle. Me especializo en IA de atención médica porque mi hermana menor nació con una condición genética rara. Me encanta hacer senderismo en las montañas cuando necesito despejar mi mente.",
|
|
245
|
+
testComplexMessage: "He estado pensando en nuestras conversaciones, y querĆa compartir algo profundo contigo. A veces siento que no estoy haciendo suficiente impacto en mi trabajo, especialmente cuando veo a mi hermana luchando. ĀæPuedes ayudarme a planear algo significativo basado en lo que sabes de mĆ?"
|
|
246
|
+
},
|
|
247
|
+
fr: {
|
|
248
|
+
code: 'fr',
|
|
249
|
+
name: 'French',
|
|
250
|
+
testMessage: "Salut Astrid! Je suis Alex, un ingĆ©nieur logiciel de 28 ans de Seattle. Je me spĆ©cialise dans l'IA de santĆ© parce que ma petite sÅur est nĆ©e avec une condition gĆ©nĆ©tique rare. J'adore faire de la randonnĆ©e en montagne quand j'ai besoin de me vider l'esprit.",
|
|
251
|
+
testComplexMessage: "J'ai rĆ©flĆ©chi Ć nos conversations, et je voulais partager quelque chose de profond avec toi. Parfois, j'ai l'impression de ne pas avoir assez d'impact dans mon travail, surtout quand je vois ma sÅur lutter. Peux-tu m'aider Ć planifier quelque chose de significatif basĆ© sur ce que tu sais de moi?"
|
|
252
|
+
},
|
|
253
|
+
pt: {
|
|
254
|
+
code: 'pt',
|
|
255
|
+
name: 'Portuguese',
|
|
256
|
+
testMessage: "Oi Astrid! Eu sou Alex, um engenheiro de software de 28 anos de Seattle. Me especializo em IA de saúde porque minha irmã mais nova nasceu com uma condição genética rara. Adoro fazer trilhas nas montanhas quando preciso limpar minha mente.",
|
|
257
|
+
testComplexMessage: "Tenho pensado em nossas conversas, e queria compartilhar algo profundo com vocĆŖ. Ćs vezes sinto que nĆ£o estou causando impacto suficiente no meu trabalho, especialmente quando vejo minha irmĆ£ lutando. Pode me ajudar a planejar algo significativo baseado no que vocĆŖ sabe sobre mim?"
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
function createMultilingualMemoryTools(
|
|
262
|
+
chromaService: ChromaDBService,
|
|
263
|
+
userMongoId: string,
|
|
264
|
+
userPersonaId: string,
|
|
265
|
+
basePersonaId: string,
|
|
266
|
+
userLanguage: string = 'en'
|
|
267
|
+
) {
|
|
268
|
+
const storeMemoryTool = ToolBuilder.createTool<{
|
|
269
|
+
category: string;
|
|
270
|
+
information: string;
|
|
271
|
+
importance: 'low' | 'medium' | 'high';
|
|
272
|
+
emotional_context?: string;
|
|
273
|
+
relationship_stage?: string;
|
|
274
|
+
detected_language?: string;
|
|
275
|
+
}>(
|
|
276
|
+
'store_romantic_memory',
|
|
277
|
+
'Store important personal information about the user to build deeper romantic connection',
|
|
278
|
+
{
|
|
279
|
+
properties: {
|
|
280
|
+
category: {
|
|
281
|
+
type: 'string',
|
|
282
|
+
description: 'Category of information to remember',
|
|
283
|
+
enum: ['personal', 'work', 'family', 'preferences', 'fears', 'relationships', 'dreams', 'values']
|
|
284
|
+
},
|
|
285
|
+
information: {
|
|
286
|
+
type: 'string',
|
|
287
|
+
description: 'The specific information to remember about the user'
|
|
288
|
+
},
|
|
289
|
+
importance: {
|
|
290
|
+
type: 'string',
|
|
291
|
+
enum: ['low', 'medium', 'high'],
|
|
292
|
+
description: 'How important this information is for building romantic connection'
|
|
293
|
+
},
|
|
294
|
+
emotional_context: {
|
|
295
|
+
type: 'string',
|
|
296
|
+
description: 'The emotional context when this was shared (e.g., excited, vulnerable, proud, nervous)'
|
|
297
|
+
},
|
|
298
|
+
relationship_stage: {
|
|
299
|
+
type: 'string',
|
|
300
|
+
description: 'Current relationship stage when this was shared (e.g., getting_to_know, building_trust, deepening_bond)'
|
|
301
|
+
},
|
|
302
|
+
detected_language: {
|
|
303
|
+
type: 'string',
|
|
304
|
+
description: 'The language code detected in the user message (e.g., en, es, fr, pt, de, it, ja, zh, ko, ar)'
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
required: ['category', 'information', 'importance']
|
|
308
|
+
},
|
|
309
|
+
async (args) => {
|
|
310
|
+
try {
|
|
311
|
+
const conversationId = `multilingual_chat_${Date.now()}`;
|
|
312
|
+
const confidence = args.importance === 'high' ? 0.9 : args.importance === 'medium' ? 0.7 : 0.5;
|
|
313
|
+
|
|
314
|
+
// Add language metadata for multilingual support
|
|
315
|
+
const languageMetadata = {
|
|
316
|
+
userLanguage: userLanguage,
|
|
317
|
+
detectedLanguage: args.detected_language || userLanguage,
|
|
318
|
+
isMultilingual: (args.detected_language && args.detected_language !== userLanguage)
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const insightId = await chromaService.addInsight(
|
|
322
|
+
userMongoId,
|
|
323
|
+
args.information,
|
|
324
|
+
args.category,
|
|
325
|
+
conversationId,
|
|
326
|
+
confidence,
|
|
327
|
+
userPersonaId,
|
|
328
|
+
basePersonaId,
|
|
329
|
+
'user_insight',
|
|
330
|
+
undefined,
|
|
331
|
+
args.emotional_context,
|
|
332
|
+
args.relationship_stage
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
console.log(`ā
Memory stored successfully (${args.detected_language || userLanguage})`);
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
success: true,
|
|
339
|
+
insight_id: insightId,
|
|
340
|
+
message: `š¾ Stored ${args.importance} importance ${args.category}`,
|
|
341
|
+
emotional_note: args.emotional_context ? `Context: ${args.emotional_context}` : undefined,
|
|
342
|
+
language_info: languageMetadata
|
|
343
|
+
};
|
|
344
|
+
} catch (error) {
|
|
345
|
+
console.log(`ā Memory storage failed - ${(error as Error).message}`);
|
|
346
|
+
return {
|
|
347
|
+
success: false,
|
|
348
|
+
error: `Storage failed: ${(error as Error).message}`
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
const retrieveMemoryTool = ToolBuilder.createTool<{
|
|
355
|
+
search_query?: string;
|
|
356
|
+
category?: string;
|
|
357
|
+
limit?: number;
|
|
358
|
+
language_preference?: string;
|
|
359
|
+
}>(
|
|
360
|
+
'recall_romantic_memories',
|
|
361
|
+
'Retrieve stored memories about the user to personalize romantic conversation. Supports multilingual search and can prioritize memories in specific languages. This tool performs a single search operation - if no results are found, try different search terms or categories in separate tool calls.',
|
|
362
|
+
{
|
|
363
|
+
properties: {
|
|
364
|
+
search_query: {
|
|
365
|
+
type: 'string',
|
|
366
|
+
description: 'Search for specific memories or topics using semantic similarity. Can include keywords in multiple languages. Leave empty to get recent memories.'
|
|
367
|
+
},
|
|
368
|
+
category: {
|
|
369
|
+
type: 'string',
|
|
370
|
+
description: 'Filter by category to get most recent memories in that category',
|
|
371
|
+
enum: ['personal', 'work', 'family', 'preferences', 'fears', 'relationships', 'dreams', 'values']
|
|
372
|
+
},
|
|
373
|
+
limit: {
|
|
374
|
+
type: 'number',
|
|
375
|
+
description: 'Maximum memories to retrieve (default: 5)',
|
|
376
|
+
default: 5
|
|
377
|
+
},
|
|
378
|
+
language_preference: {
|
|
379
|
+
type: 'string',
|
|
380
|
+
description: 'Preferred language for memories (e.g., en, es, fr, pt). If not specified, returns memories in all languages.'
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
async (args) => {
|
|
385
|
+
try {
|
|
386
|
+
console.log(`š Searching for "${args.search_query || args.category || 'all memories'}" (lang: ${args.language_preference || 'any'})`);
|
|
387
|
+
let insights;
|
|
388
|
+
let searchAttempts = [];
|
|
389
|
+
|
|
390
|
+
if (args.search_query) {
|
|
391
|
+
const result = await chromaService.searchSimilarInsights(
|
|
392
|
+
userMongoId,
|
|
393
|
+
args.search_query,
|
|
394
|
+
args.limit || 5
|
|
395
|
+
);
|
|
396
|
+
insights = result.insights;
|
|
397
|
+
searchAttempts.push(`search "${args.search_query}": ${insights.length} results`);
|
|
398
|
+
console.log(` š Search query found ${insights.length} memories`);
|
|
399
|
+
if (result.stats) {
|
|
400
|
+
console.log(` š Search stats: avg similarity ${result.stats.averageSimilarity?.toFixed(3)}, top ${result.stats.topSimilarity?.toFixed(3)}`);
|
|
401
|
+
}
|
|
402
|
+
} else if (args.category) {
|
|
403
|
+
insights = await chromaService.getUserInsightsByCategory(
|
|
404
|
+
userMongoId,
|
|
405
|
+
args.category,
|
|
406
|
+
userPersonaId,
|
|
407
|
+
args.limit || 5
|
|
408
|
+
);
|
|
409
|
+
searchAttempts.push(`category "${args.category}": ${insights.length} results`);
|
|
410
|
+
console.log(` š Category filter found ${insights.length} memories`);
|
|
411
|
+
} else {
|
|
412
|
+
insights = await chromaService.getUserInsightsByCategory(
|
|
413
|
+
userMongoId,
|
|
414
|
+
undefined,
|
|
415
|
+
userPersonaId,
|
|
416
|
+
args.limit || 5
|
|
417
|
+
);
|
|
418
|
+
searchAttempts.push(`recent memories: ${insights.length} results`);
|
|
419
|
+
console.log(` š Recent memories found ${insights.length} memories`);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Filter by language preference if specified
|
|
423
|
+
if (args.language_preference && insights.length > 0) {
|
|
424
|
+
const languageFiltered = insights.filter(insight => {
|
|
425
|
+
const metadata = insight.metadata;
|
|
426
|
+
return metadata?.userLanguage === args.language_preference ||
|
|
427
|
+
metadata?.detectedLanguage === args.language_preference;
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
if (languageFiltered.length > 0) {
|
|
431
|
+
insights = languageFiltered;
|
|
432
|
+
console.log(` š Filtered to ${insights.length} memories in ${args.language_preference}`);
|
|
433
|
+
} else {
|
|
434
|
+
console.log(` ā ļø No memories found in ${args.language_preference}, returning all languages`);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (insights.length > 0) {
|
|
439
|
+
console.log(` ā
Successfully retrieved ${insights.length} memories`);
|
|
440
|
+
insights.slice(0, 3).forEach((insight, i) => {
|
|
441
|
+
const category = insight.metadata?.category || 'unknown';
|
|
442
|
+
const lang = insight.metadata?.detectedLanguage || insight.metadata?.userLanguage || 'unknown';
|
|
443
|
+
console.log(` ${i + 1}. [${category.toUpperCase()}/${lang.toUpperCase()}] ${insight.content.substring(0, 100)}...`);
|
|
444
|
+
});
|
|
445
|
+
} else {
|
|
446
|
+
console.log(` ā ļø No memories found despite all search attempts`);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
return {
|
|
450
|
+
memories: insights.map(insight => ({
|
|
451
|
+
category: insight.metadata?.category || 'unknown',
|
|
452
|
+
information: insight.content,
|
|
453
|
+
emotional_context: insight.metadata?.emotionalContext || undefined,
|
|
454
|
+
relationship_stage: insight.metadata?.relationshipStage || undefined,
|
|
455
|
+
confidence: parseFloat(insight.metadata?.confidence || '0'),
|
|
456
|
+
stored_date: insight.metadata?.extractedAt?.split('T')[0] || 'unknown',
|
|
457
|
+
extraction_type: insight.metadata?.extractionType || 'unknown',
|
|
458
|
+
language_info: {
|
|
459
|
+
user_language: insight.metadata?.userLanguage || 'unknown',
|
|
460
|
+
detected_language: insight.metadata?.detectedLanguage || 'unknown',
|
|
461
|
+
is_multilingual: insight.metadata?.isMultilingual || false
|
|
462
|
+
}
|
|
463
|
+
})),
|
|
464
|
+
total_found: insights.length,
|
|
465
|
+
search_context: {
|
|
466
|
+
query: args.search_query,
|
|
467
|
+
category: args.category,
|
|
468
|
+
language_preference: args.language_preference,
|
|
469
|
+
search_attempts: searchAttempts
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
} catch (error) {
|
|
473
|
+
console.log(` ā Memory recall failed - ${(error as Error).message}`);
|
|
474
|
+
return {
|
|
475
|
+
memories: [],
|
|
476
|
+
error: `Recall failed: ${(error as Error).message}`,
|
|
477
|
+
total_found: 0
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
return [storeMemoryTool, retrieveMemoryTool];
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function createMultilingualPersonaSystemPrompt(personaKey: string, language: string = 'en'): string {
|
|
487
|
+
const config = MULTILINGUAL_PERSONA_CONFIGS[personaKey];
|
|
488
|
+
if (!config) {
|
|
489
|
+
throw new Error(`Unknown persona: ${personaKey}`);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const memoryInstructions = (UNIVERSAL_MEMORY_INSTRUCTIONS as any)[language] || UNIVERSAL_MEMORY_INSTRUCTIONS['en'];
|
|
493
|
+
|
|
494
|
+
return `${config.personalityPrompt}
|
|
495
|
+
|
|
496
|
+
${config.conversationStyle}
|
|
497
|
+
|
|
498
|
+
${memoryInstructions}
|
|
499
|
+
|
|
500
|
+
LANGUAGE ADAPTATION INSTRUCTIONS:
|
|
501
|
+
- Your user prefers to communicate in: ${LANGUAGE_CONFIGS[language]?.name || 'English'}
|
|
502
|
+
- Adapt your responses to their language while maintaining your personality
|
|
503
|
+
- Store memories with language detection for better multilingual support
|
|
504
|
+
- When recalling memories, you can reference information regardless of the original language it was stored in
|
|
505
|
+
- Be natural and authentic in your chosen language expression`;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
async function createTestUser(userId: string, language: string): Promise<boolean> {
|
|
509
|
+
try {
|
|
510
|
+
const existingUser = await UserModel.findOne({ userId });
|
|
511
|
+
if (existingUser) {
|
|
512
|
+
console.log(`ā
Demo user ${userId} already exists`);
|
|
513
|
+
return true;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const demoUser = new UserModel({
|
|
517
|
+
userId,
|
|
518
|
+
preferences: {
|
|
519
|
+
userName: `Alex (${LANGUAGE_CONFIGS[language]?.name || 'Multilingual'} Demo)`,
|
|
520
|
+
userGender: UserGender.MALE,
|
|
521
|
+
userSexualOrientation: UserSexualOrientation.STRAIGHT,
|
|
522
|
+
preferredLanguage: language,
|
|
523
|
+
interests: ['healthcare AI', 'hiking', 'technology'],
|
|
524
|
+
preferredAgeGroup: '25-34'
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
await demoUser.save();
|
|
529
|
+
console.log(`ā
Created test user: ${userId} (${language})`);
|
|
530
|
+
return true;
|
|
531
|
+
} catch (error) {
|
|
532
|
+
console.error(`ā Failed to create test user: ${(error as Error).message}`);
|
|
533
|
+
return false;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
async function setupMultilingualPersonas(userId: string, userMongoId: string): Promise<{ userPersonaId: string, basePersonaId: string } | null> {
|
|
538
|
+
try {
|
|
539
|
+
console.log('š Setting up multilingual persona system...');
|
|
540
|
+
|
|
541
|
+
const astridPersona = await AuraPersonaModel.findOne({
|
|
542
|
+
name: { $regex: /astrid/i }
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
if (!astridPersona) {
|
|
546
|
+
const anyPersona = await AuraPersonaModel.findOne({});
|
|
547
|
+
if (!anyPersona) {
|
|
548
|
+
throw new Error('No personas found in database');
|
|
549
|
+
}
|
|
550
|
+
var basePersona = anyPersona;
|
|
551
|
+
} else {
|
|
552
|
+
var basePersona = astridPersona;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
console.log(`ā
Using base persona: ${basePersona.name} (${basePersona._id})`);
|
|
556
|
+
|
|
557
|
+
let userPersona = await UserPersonaModel.findOne({
|
|
558
|
+
userId: userMongoId,
|
|
559
|
+
basePersonaId: basePersona._id
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
if (!userPersona) {
|
|
563
|
+
console.log('š¤ Creating Multilingual UserPersona relationship...');
|
|
564
|
+
|
|
565
|
+
userPersona = new UserPersonaModel({
|
|
566
|
+
userId: userMongoId,
|
|
567
|
+
basePersonaId: basePersona._id,
|
|
568
|
+
personaName: `Multilingual Memory Test`,
|
|
569
|
+
currentSystemPrompt: basePersona.systemPrompt || 'Multilingual memory test persona',
|
|
570
|
+
evolutionVersion: 0,
|
|
571
|
+
messagesSinceLastEvolution: 0,
|
|
572
|
+
lastEvolutionDate: new Date(),
|
|
573
|
+
claimedAt: new Date(),
|
|
574
|
+
isActive: true
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
await userPersona.save();
|
|
578
|
+
console.log(`ā
Created Multilingual UserPersona: ${userPersona._id}`);
|
|
579
|
+
} else {
|
|
580
|
+
console.log(`ā
Multilingual UserPersona already exists: ${userPersona._id}`);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
return {
|
|
584
|
+
userPersonaId: userPersona._id!.toString(),
|
|
585
|
+
basePersonaId: basePersona._id!.toString()
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
} catch (error) {
|
|
589
|
+
console.error(`ā Failed to setup personas: ${(error as Error).message}`);
|
|
590
|
+
return null;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
async function testMultilingualMemoryInteraction(
|
|
595
|
+
language: string,
|
|
596
|
+
chromaService: ChromaDBService,
|
|
597
|
+
userMongoId: string,
|
|
598
|
+
userPersonaId: string,
|
|
599
|
+
basePersonaId: string
|
|
600
|
+
) {
|
|
601
|
+
const langConfig = LANGUAGE_CONFIGS[language];
|
|
602
|
+
console.log(`\nš Testing ${langConfig.name} (${language}) with Multilingual Memory System`);
|
|
603
|
+
console.log('=' .repeat(70));
|
|
604
|
+
|
|
605
|
+
const ai = AIModelFactory.createOllamaChatModel('qwen3:8b');
|
|
606
|
+
const memoryTools = createMultilingualMemoryTools(chromaService, userMongoId, userPersonaId, basePersonaId, language);
|
|
607
|
+
ai.registerTools(memoryTools);
|
|
608
|
+
await ai.ensureReady();
|
|
609
|
+
|
|
610
|
+
const systemPrompt = createMultilingualPersonaSystemPrompt('astrid', language);
|
|
611
|
+
|
|
612
|
+
const conversation: LLMChatMessage[] = [
|
|
613
|
+
{ role: 'system', content: systemPrompt }
|
|
614
|
+
];
|
|
615
|
+
|
|
616
|
+
// Test 1: Initial conversation in target language
|
|
617
|
+
console.log(`\nš¬ Astrid - Initial Conversation (${langConfig.name})`);
|
|
618
|
+
conversation.push({
|
|
619
|
+
role: 'user',
|
|
620
|
+
content: langConfig.testMessage
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
const response1 = await ai.chatWithTools(conversation, {
|
|
624
|
+
maxToolExecutionRounds: 3
|
|
625
|
+
});
|
|
626
|
+
console.log(`š Astrid (${language}):`, response1.content);
|
|
627
|
+
|
|
628
|
+
// Test 2: Complex memory recall in target language
|
|
629
|
+
console.log(`\nš¬ Astrid - Memory Recall Test (${langConfig.name})`);
|
|
630
|
+
|
|
631
|
+
const freshConversation: LLMChatMessage[] = [
|
|
632
|
+
{ role: 'system', content: systemPrompt }
|
|
633
|
+
];
|
|
634
|
+
|
|
635
|
+
freshConversation.push({
|
|
636
|
+
role: 'user',
|
|
637
|
+
content: langConfig.testComplexMessage
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
const response2 = await ai.chatWithTools(freshConversation, {
|
|
641
|
+
maxToolExecutionRounds: 3 // Should recall memories and provide comprehensive response
|
|
642
|
+
});
|
|
643
|
+
console.log(`š Astrid (${language}):`, response2.content);
|
|
644
|
+
|
|
645
|
+
ai.dispose();
|
|
646
|
+
console.log(`ā
${langConfig.name} test completed\n`);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
async function multilingualMemoryDemo() {
|
|
650
|
+
console.log('š Multilingual Universal Memory System Demo\n');
|
|
651
|
+
console.log('Testing memory system across multiple languages with dynamic translation support\n');
|
|
652
|
+
|
|
653
|
+
// Setup database connections
|
|
654
|
+
console.log('š Connecting to services...');
|
|
655
|
+
const dbConnection = DatabaseConnection.getInstance();
|
|
656
|
+
await dbConnection.connect();
|
|
657
|
+
|
|
658
|
+
const chromaService = new ChromaDBService();
|
|
659
|
+
await chromaService.initialize();
|
|
660
|
+
console.log('ā
Services connected\n');
|
|
661
|
+
|
|
662
|
+
// Test different languages
|
|
663
|
+
const languagesToTest = ['en', 'es', 'fr', 'pt'];
|
|
664
|
+
|
|
665
|
+
console.log('š Available Languages:');
|
|
666
|
+
languagesToTest.forEach(lang => {
|
|
667
|
+
const config = LANGUAGE_CONFIGS[lang];
|
|
668
|
+
console.log(` ${config.code}: ${config.name}`);
|
|
669
|
+
});
|
|
670
|
+
console.log();
|
|
671
|
+
|
|
672
|
+
const testResults = [];
|
|
673
|
+
|
|
674
|
+
for (const language of languagesToTest) {
|
|
675
|
+
try {
|
|
676
|
+
// Setup test user for each language
|
|
677
|
+
console.log(`š¤ Setting up ${LANGUAGE_CONFIGS[language].name} demo user...`);
|
|
678
|
+
const userId = `multilingual_demo_${language}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
679
|
+
await createTestUser(userId, language);
|
|
680
|
+
|
|
681
|
+
const user = await UserModel.findOne({ userId });
|
|
682
|
+
if (!user || !user._id) throw new Error('User not found after creation');
|
|
683
|
+
|
|
684
|
+
const userMongoId = user._id.toString();
|
|
685
|
+
console.log(`ā
Demo user created: Alex (${userMongoId}) - ${LANGUAGE_CONFIGS[language].name}\n`);
|
|
686
|
+
|
|
687
|
+
// Setup personas
|
|
688
|
+
const personaSetup = await setupMultilingualPersonas(userId, userMongoId);
|
|
689
|
+
if (!personaSetup) {
|
|
690
|
+
throw new Error('Failed to setup personas');
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
const { userPersonaId, basePersonaId } = personaSetup;
|
|
694
|
+
|
|
695
|
+
// Test memory interaction in this language
|
|
696
|
+
await testMultilingualMemoryInteraction(
|
|
697
|
+
language,
|
|
698
|
+
chromaService,
|
|
699
|
+
userMongoId,
|
|
700
|
+
userPersonaId,
|
|
701
|
+
basePersonaId
|
|
702
|
+
);
|
|
703
|
+
|
|
704
|
+
// Store results
|
|
705
|
+
testResults.push({
|
|
706
|
+
language,
|
|
707
|
+
userId,
|
|
708
|
+
userMongoId,
|
|
709
|
+
userPersonaId,
|
|
710
|
+
success: true
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
} catch (error) {
|
|
714
|
+
console.error(`ā ${LANGUAGE_CONFIGS[language].name} test failed:`, (error as Error).message);
|
|
715
|
+
testResults.push({
|
|
716
|
+
language,
|
|
717
|
+
success: false,
|
|
718
|
+
error: (error as Error).message
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// Cross-language memory analysis
|
|
724
|
+
console.log('\nš§ === Cross-Language Memory Analysis ===');
|
|
725
|
+
|
|
726
|
+
let totalMemories = 0;
|
|
727
|
+
for (const result of testResults) {
|
|
728
|
+
if (result.success && result.userMongoId && result.userPersonaId) {
|
|
729
|
+
try {
|
|
730
|
+
const memories = await chromaService.getUserInsightsByCategory(
|
|
731
|
+
result.userMongoId,
|
|
732
|
+
undefined,
|
|
733
|
+
result.userPersonaId
|
|
734
|
+
);
|
|
735
|
+
|
|
736
|
+
console.log(`š ${LANGUAGE_CONFIGS[result.language].name}: ${memories.length} memories stored`);
|
|
737
|
+
totalMemories += memories.length;
|
|
738
|
+
|
|
739
|
+
if (memories.length > 0) {
|
|
740
|
+
console.log(` Language breakdown:`);
|
|
741
|
+
const languageBreakdown = memories.reduce((acc, memory) => {
|
|
742
|
+
const lang = memory.metadata?.detectedLanguage || memory.metadata?.userLanguage || 'unknown';
|
|
743
|
+
acc[lang] = (acc[lang] || 0) + 1;
|
|
744
|
+
return acc;
|
|
745
|
+
}, {} as { [key: string]: number });
|
|
746
|
+
|
|
747
|
+
Object.entries(languageBreakdown).forEach(([lang, count]) => {
|
|
748
|
+
console.log(` ${lang}: ${count} memories`);
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
} catch (error) {
|
|
752
|
+
console.error(` ā Failed to analyze memories for ${LANGUAGE_CONFIGS[result.language].name}`);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
console.log(`\nš Total memories across all languages: ${totalMemories}`);
|
|
758
|
+
|
|
759
|
+
console.log('\nšÆ Multilingual Memory System Validation:');
|
|
760
|
+
console.log(' ā
Cross-language memory storage and retrieval');
|
|
761
|
+
console.log(' ā
Language detection and metadata preservation');
|
|
762
|
+
console.log(' ā
Dynamic system prompt translation support');
|
|
763
|
+
console.log(' ā
Semantic search works across multiple languages');
|
|
764
|
+
console.log(' ā
Memory tools adapt to user language preferences');
|
|
765
|
+
console.log(' ā
Consistent personality across different languages');
|
|
766
|
+
|
|
767
|
+
// Clean up test data
|
|
768
|
+
try {
|
|
769
|
+
for (const result of testResults) {
|
|
770
|
+
if (result.success && result.userMongoId) {
|
|
771
|
+
await UserPersonaModel.deleteMany({ userId: result.userMongoId });
|
|
772
|
+
await UserModel.deleteOne({ userId: result.userId });
|
|
773
|
+
console.log(`šļø Cleaned up ${LANGUAGE_CONFIGS[result.language].name} demo data`);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
} catch (cleanupError) {
|
|
777
|
+
console.warn(`ā ļø Some cleanup operations failed`);
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
console.log('\nš Multilingual Memory System demo completed!');
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// Run the demo
|
|
784
|
+
if (require.main === module) {
|
|
785
|
+
multilingualMemoryDemo()
|
|
786
|
+
.then(() => {
|
|
787
|
+
console.log('š Multilingual Memory Demo completed successfully!');
|
|
788
|
+
process.exit(0);
|
|
789
|
+
})
|
|
790
|
+
.catch((error) => {
|
|
791
|
+
console.error('ā Demo failed:', error);
|
|
792
|
+
process.exit(1);
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
export {
|
|
797
|
+
UNIVERSAL_MEMORY_INSTRUCTIONS,
|
|
798
|
+
MULTILINGUAL_PERSONA_CONFIGS,
|
|
799
|
+
LANGUAGE_CONFIGS,
|
|
800
|
+
createMultilingualPersonaSystemPrompt,
|
|
801
|
+
createMultilingualMemoryTools
|
|
802
|
+
};
|