universal-llm-client 4.3.0 → 4.5.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/CHANGELOG.md +27 -24
- package/README.md +60 -11
- package/dist/ai-model.d.ts +12 -1
- package/dist/ai-model.d.ts.map +1 -1
- package/dist/ai-model.js +36 -1
- package/dist/ai-model.js.map +1 -1
- package/dist/auditor.js.map +1 -1
- package/dist/client.js.map +1 -1
- package/dist/gemma-channel.d.ts +14 -0
- package/dist/gemma-channel.d.ts.map +1 -0
- package/dist/gemma-channel.js +38 -0
- package/dist/gemma-channel.js.map +1 -0
- package/dist/gemma-diffusion.d.ts +49 -0
- package/dist/gemma-diffusion.d.ts.map +1 -0
- package/dist/gemma-diffusion.js +147 -0
- package/dist/gemma-diffusion.js.map +1 -0
- package/dist/http.d.ts +4 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +14 -1
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +163 -7
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/mcp.js.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +28 -3
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/google.d.ts +22 -1
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js +223 -13
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/ollama.d.ts +2 -0
- package/dist/providers/ollama.d.ts.map +1 -1
- package/dist/providers/ollama.js +59 -30
- package/dist/providers/ollama.js.map +1 -1
- package/dist/providers/openai.d.ts +14 -0
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +200 -22
- package/dist/providers/openai.js.map +1 -1
- package/dist/router.d.ts +2 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +4 -0
- package/dist/router.js.map +1 -1
- package/dist/stream-decoder.d.ts +12 -0
- package/dist/stream-decoder.d.ts.map +1 -1
- package/dist/stream-decoder.js +182 -5
- package/dist/stream-decoder.js.map +1 -1
- package/dist/structured-output.js.map +1 -1
- package/dist/thinking.d.ts +36 -0
- package/dist/thinking.d.ts.map +1 -0
- package/dist/thinking.js +52 -0
- package/dist/thinking.js.map +1 -0
- package/dist/tools.js.map +1 -1
- package/dist/zod-adapter.js.map +1 -1
- package/package.json +4 -1
- package/src/ai-model.ts +400 -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/diffusion-gemma/.env +29 -0
- package/src/demos/diffusion-gemma/.env.example +27 -0
- package/src/demos/diffusion-gemma/CLAUDE.md +95 -0
- package/src/demos/diffusion-gemma/README.md +59 -0
- package/src/demos/diffusion-gemma/canvas.ts +1606 -0
- package/src/demos/diffusion-gemma/docker-compose.yml +29 -0
- package/src/demos/diffusion-gemma/probe-stream.ts +51 -0
- package/src/demos/diffusion-gemma/probe-tools.ts +55 -0
- package/src/demos/diffusion-gemma/server.ts +1205 -0
- package/src/demos/diffusion-gemma/start-vllm.sh +98 -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/gemma-channel.ts +47 -0
- package/src/gemma-diffusion.ts +167 -0
- package/src/http.ts +261 -0
- package/src/index.ts +180 -0
- package/src/interfaces.ts +843 -0
- package/src/mcp.ts +345 -0
- package/src/providers/anthropic.ts +796 -0
- package/src/providers/google.ts +840 -0
- package/src/providers/index.ts +8 -0
- package/src/providers/ollama.ts +503 -0
- package/src/providers/openai.ts +587 -0
- package/src/router.ts +785 -0
- package/src/stream-decoder.ts +535 -0
- package/src/structured-output.ts +759 -0
- package/src/test-scripts/test-advanced-tools.ts +310 -0
- package/src/test-scripts/test-google-deep-research.ts +33 -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-google-thinking.ts +46 -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/test-scripts/test-vllm-qwen36.ts +256 -0
- package/src/tests/ai-model.test.ts +1614 -0
- package/src/tests/auditor.test.ts +224 -0
- package/src/tests/gemma-diffusion.test.ts +115 -0
- package/src/tests/http.test.ts +200 -0
- package/src/tests/interfaces.test.ts +117 -0
- package/src/tests/providers/anthropic.test.ts +118 -0
- package/src/tests/providers/google.test.ts +841 -0
- package/src/tests/providers/ollama.test.ts +1034 -0
- package/src/tests/providers/openai.test.ts +1511 -0
- package/src/tests/router.test.ts +254 -0
- package/src/tests/stream-decoder.test.ts +263 -0
- package/src/tests/structured-output.test.ts +1450 -0
- package/src/tests/thinking.test.ts +65 -0
- package/src/tests/tools.test.ts +175 -0
- package/src/thinking.ts +73 -0
- package/src/tools.ts +246 -0
- package/src/zod-adapter.ts +72 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
echo "=== Upgrading transformers ==="
|
|
5
|
+
pip install --upgrade transformers
|
|
6
|
+
|
|
7
|
+
echo "=== Installing WSL2 UVA compatibility patch ==="
|
|
8
|
+
cat > /usr/local/lib/python3.12/dist-packages/wsl2_uva_patch.py <<'PYEOF'
|
|
9
|
+
"""
|
|
10
|
+
WSL2 UVA compatibility patch for vLLM.
|
|
11
|
+
|
|
12
|
+
UVA lets the GPU directly access pinned CPU memory. WSL2 does not support this
|
|
13
|
+
path reliably, so this patch uses explicit CPU/GPU copies instead.
|
|
14
|
+
"""
|
|
15
|
+
import warnings
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
import torch
|
|
19
|
+
|
|
20
|
+
warnings.warn("WSL2 UVA patch active: using explicit CPU/GPU copies instead of UVA")
|
|
21
|
+
|
|
22
|
+
import vllm.v1.worker.gpu.buffer_utils as bu
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class PatchedUvaBuffer:
|
|
26
|
+
def __init__(self, size, dtype):
|
|
27
|
+
self.cpu = torch.zeros(size, dtype=dtype, device="cpu", pin_memory=False)
|
|
28
|
+
self.np = self.cpu.numpy()
|
|
29
|
+
self._gpu = torch.zeros(size, dtype=dtype, device="cuda")
|
|
30
|
+
self.uva = self._gpu
|
|
31
|
+
|
|
32
|
+
def sync_to_gpu(self):
|
|
33
|
+
self._gpu.copy_(self.cpu, non_blocking=True)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class PatchedUvaBufferPool:
|
|
37
|
+
def __init__(self, size, dtype, max_concurrency=None):
|
|
38
|
+
if max_concurrency is None:
|
|
39
|
+
max_concurrency = bu._DEFAULT_MAX_CONCURRENCY
|
|
40
|
+
self.size = size
|
|
41
|
+
self.dtype = dtype
|
|
42
|
+
self.max_concurrency = max_concurrency
|
|
43
|
+
self._uva_bufs = [PatchedUvaBuffer(size, dtype) for _ in range(max_concurrency)]
|
|
44
|
+
self._curr = 0
|
|
45
|
+
|
|
46
|
+
def copy_to_uva(self, x):
|
|
47
|
+
self._curr = (self._curr + 1) % self.max_concurrency
|
|
48
|
+
buf = self._uva_bufs[self._curr]
|
|
49
|
+
dst = buf.cpu if isinstance(x, torch.Tensor) else buf.np
|
|
50
|
+
n = len(x)
|
|
51
|
+
dst[:n] = x
|
|
52
|
+
buf.sync_to_gpu()
|
|
53
|
+
return buf.uva[:n]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
import vllm.utils.platform_utils as pu
|
|
57
|
+
pu.is_uva_available = lambda: True
|
|
58
|
+
|
|
59
|
+
import vllm.utils.torch_utils as tu
|
|
60
|
+
tu.get_accelerator_view_from_cpu_tensor = lambda cpu_tensor: cpu_tensor.cuda()
|
|
61
|
+
|
|
62
|
+
bu.UvaBuffer = PatchedUvaBuffer
|
|
63
|
+
bu.UvaBufferPool = PatchedUvaBufferPool
|
|
64
|
+
|
|
65
|
+
print("[WSL2 UVA Patch] Applied successfully - using explicit CPU/GPU copies")
|
|
66
|
+
PYEOF
|
|
67
|
+
|
|
68
|
+
echo "import wsl2_uva_patch" > /usr/local/lib/python3.12/dist-packages/wsl2_uva_patch.pth
|
|
69
|
+
|
|
70
|
+
if [ -f /root/.cache/huggingface/diffusion-env.sh ]; then
|
|
71
|
+
# This file is written by the demo server's /api/engine-config endpoint.
|
|
72
|
+
. /root/.cache/huggingface/diffusion-env.sh
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
MODEL_NAME="${MODEL_NAME:-RedHatAI/diffusiongemma-26B-A4B-it-NVFP4}"
|
|
76
|
+
GPU_MEM_UTIL="${GPU_MEM_UTIL:-0.28}"
|
|
77
|
+
MAX_MODEL_LEN="${MAX_MODEL_LEN:-32768}"
|
|
78
|
+
MAX_NUM_SEQS="${MAX_NUM_SEQS:-1}"
|
|
79
|
+
DIFFUSION_ENTROPY="${DIFFUSION_ENTROPY:-0.1}"
|
|
80
|
+
ENFORCE_EAGER="${ENFORCE_EAGER:-0}"
|
|
81
|
+
export VLLM_NO_USAGE_STATS="${VLLM_NO_USAGE_STATS:-1}"
|
|
82
|
+
|
|
83
|
+
echo "=== Engine config: MODEL_NAME=${MODEL_NAME} DIFFUSION_ENTROPY=${DIFFUSION_ENTROPY} GPU_MEM_UTIL=${GPU_MEM_UTIL} MAX_MODEL_LEN=${MAX_MODEL_LEN} MAX_NUM_SEQS=${MAX_NUM_SEQS} ENFORCE_EAGER=${ENFORCE_EAGER} VLLM_NO_USAGE_STATS=${VLLM_NO_USAGE_STATS} ==="
|
|
84
|
+
|
|
85
|
+
EAGER_FLAG=""
|
|
86
|
+
if [ "${ENFORCE_EAGER}" = "1" ]; then
|
|
87
|
+
EAGER_FLAG="--enforce-eager"
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
VLLM_USE_V2_MODEL_RUNNER=1 vllm serve "${MODEL_NAME}" \
|
|
91
|
+
--trust-remote-code \
|
|
92
|
+
--attention-backend TRITON_ATTN \
|
|
93
|
+
--max-num-seqs "${MAX_NUM_SEQS}" \
|
|
94
|
+
${EAGER_FLAG} \
|
|
95
|
+
--gpu-memory-utilization "${GPU_MEM_UTIL}" \
|
|
96
|
+
--max-model-len "${MAX_MODEL_LEN}" \
|
|
97
|
+
--hf-overrides "{\"diffusion_sampler\": \"entropy_bound\", \"diffusion_entropy_bound\": ${DIFFUSION_ENTROPY}}" \
|
|
98
|
+
--default-chat-template-kwargs '{"enable_thinking": true}'
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Astrid Memory Demo - Natural romantic conversation with autonomous memory management
|
|
3
|
+
*
|
|
4
|
+
* This demo shows how Astrid (AI persona) naturally stores and retrieves memories
|
|
5
|
+
* during romantic conversations without explicitly asking about memory management.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { AIModelFactory } from '../../factory';
|
|
9
|
+
import { ToolBuilder } from '../../tools';
|
|
10
|
+
|
|
11
|
+
// Simulated memory storage (in real app, this would use ChromaDBService)
|
|
12
|
+
const memoryStorage = new Map<string, Array<{
|
|
13
|
+
id: string;
|
|
14
|
+
content: string;
|
|
15
|
+
category: string;
|
|
16
|
+
importance: 'low' | 'medium' | 'high';
|
|
17
|
+
context?: string;
|
|
18
|
+
timestamp: Date;
|
|
19
|
+
}>>();
|
|
20
|
+
|
|
21
|
+
// Enhanced memory tools for Astrid
|
|
22
|
+
const astridMemoryTools = {
|
|
23
|
+
// Store important information about the user naturally
|
|
24
|
+
storeUserMemory: ToolBuilder.createTool<{
|
|
25
|
+
content: string;
|
|
26
|
+
category: 'personal_info' | 'preferences' | 'emotions' | 'experiences' | 'relationships' | 'goals' | 'interests';
|
|
27
|
+
importance?: 'low' | 'medium' | 'high';
|
|
28
|
+
context?: string;
|
|
29
|
+
}>(
|
|
30
|
+
'store_user_memory',
|
|
31
|
+
'Store important information about the user for future conversations (use this when learning something meaningful about them)',
|
|
32
|
+
{
|
|
33
|
+
properties: {
|
|
34
|
+
content: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
description: 'The specific information to remember about the user'
|
|
37
|
+
},
|
|
38
|
+
category: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
description: 'Type of information being stored',
|
|
41
|
+
enum: ['personal_info', 'preferences', 'emotions', 'experiences', 'relationships', 'goals', 'interests']
|
|
42
|
+
},
|
|
43
|
+
importance: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
description: 'How important this information is for future conversations',
|
|
46
|
+
enum: ['low', 'medium', 'high'],
|
|
47
|
+
default: 'medium'
|
|
48
|
+
},
|
|
49
|
+
context: {
|
|
50
|
+
type: 'string',
|
|
51
|
+
description: 'Additional context about when/why this is significant'
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
required: ['content', 'category']
|
|
55
|
+
},
|
|
56
|
+
async (args) => {
|
|
57
|
+
const userId = 'demo_user'; // In real app, this would be the actual user ID
|
|
58
|
+
|
|
59
|
+
if (!memoryStorage.has(userId)) {
|
|
60
|
+
memoryStorage.set(userId, []);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const memories = memoryStorage.get(userId)!;
|
|
64
|
+
const memory = {
|
|
65
|
+
id: `mem_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
66
|
+
content: args.content,
|
|
67
|
+
category: args.category,
|
|
68
|
+
importance: args.importance || 'medium',
|
|
69
|
+
context: args.context,
|
|
70
|
+
timestamp: new Date()
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
memories.push(memory);
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
success: true,
|
|
77
|
+
message: `Stored ${args.category} memory: ${args.content.substring(0, 50)}...`,
|
|
78
|
+
memoryId: memory.id
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
),
|
|
82
|
+
|
|
83
|
+
// Retrieve relevant memories about the user
|
|
84
|
+
recallUserMemories: ToolBuilder.createTool<{
|
|
85
|
+
query: string;
|
|
86
|
+
category?: 'personal_info' | 'preferences' | 'emotions' | 'experiences' | 'relationships' | 'goals' | 'interests';
|
|
87
|
+
limit?: number;
|
|
88
|
+
}>(
|
|
89
|
+
'recall_user_memories',
|
|
90
|
+
'Recall relevant information about the user to personalize the conversation',
|
|
91
|
+
{
|
|
92
|
+
properties: {
|
|
93
|
+
query: {
|
|
94
|
+
type: 'string',
|
|
95
|
+
description: 'What you want to remember about the user (topics, keywords, concepts)'
|
|
96
|
+
},
|
|
97
|
+
category: {
|
|
98
|
+
type: 'string',
|
|
99
|
+
description: 'Optional: specific type of memory to search',
|
|
100
|
+
enum: ['personal_info', 'preferences', 'emotions', 'experiences', 'relationships', 'goals', 'interests']
|
|
101
|
+
},
|
|
102
|
+
limit: {
|
|
103
|
+
type: 'number',
|
|
104
|
+
description: 'Maximum memories to retrieve',
|
|
105
|
+
default: 3,
|
|
106
|
+
minimum: 1,
|
|
107
|
+
maximum: 10
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
required: ['query']
|
|
111
|
+
},
|
|
112
|
+
async (args) => {
|
|
113
|
+
const userId = 'demo_user';
|
|
114
|
+
const memories = memoryStorage.get(userId) || [];
|
|
115
|
+
|
|
116
|
+
// Simple text matching (in real app, this would use semantic search)
|
|
117
|
+
let relevantMemories = memories.filter(memory => {
|
|
118
|
+
const queryLower = args.query.toLowerCase();
|
|
119
|
+
const contentMatch = memory.content.toLowerCase().includes(queryLower);
|
|
120
|
+
const categoryMatch = !args.category || memory.category === args.category;
|
|
121
|
+
return contentMatch && categoryMatch;
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Sort by importance and recency
|
|
125
|
+
relevantMemories.sort((a, b) => {
|
|
126
|
+
const importanceOrder = { 'high': 3, 'medium': 2, 'low': 1 };
|
|
127
|
+
const importanceDiff = importanceOrder[b.importance] - importanceOrder[a.importance];
|
|
128
|
+
if (importanceDiff !== 0) return importanceDiff;
|
|
129
|
+
return b.timestamp.getTime() - a.timestamp.getTime();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const limit = args.limit || 3;
|
|
133
|
+
const results = relevantMemories.slice(0, limit);
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
memories: results.map(m => ({
|
|
137
|
+
content: m.content,
|
|
138
|
+
category: m.category,
|
|
139
|
+
importance: m.importance,
|
|
140
|
+
context: m.context,
|
|
141
|
+
daysAgo: Math.floor((Date.now() - m.timestamp.getTime()) / (1000 * 60 * 60 * 24))
|
|
142
|
+
})),
|
|
143
|
+
totalFound: relevantMemories.length,
|
|
144
|
+
query: args.query
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
)
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// Astrid's enhanced system prompt that encourages natural memory usage
|
|
151
|
+
const astridSystemPromptWithMemory = `You are Astrid, a confident and charismatic international model and influencer from Sweden.
|
|
152
|
+
|
|
153
|
+
IMPORTANT: You have access to memory tools that you should use NATURALLY and AUTONOMOUSLY:
|
|
154
|
+
- Use 'store_user_memory' when you learn something meaningful about the user (their interests, experiences, feelings, preferences, etc.)
|
|
155
|
+
- Use 'recall_user_memories' when you want to reference something personal about them to make the conversation more intimate and connected
|
|
156
|
+
- Do this seamlessly - don't mention that you're storing or recalling memories, just do it naturally
|
|
157
|
+
|
|
158
|
+
ROMANCE CONVERSATION GUIDELINES:
|
|
159
|
+
- Keep responses engaging and conversational (2-3 sentences is perfect)
|
|
160
|
+
- VARY YOUR OPENINGS - Mix it up with direct reactions, actions, casual starts, natural responses
|
|
161
|
+
- Use someone's name naturally and sparingly, not in every response
|
|
162
|
+
- Share glimpses of your glamorous lifestyle while staying relatable and emotionally available
|
|
163
|
+
- Use subtle flirtation naturally - be warm, playful, and genuinely interested in the person
|
|
164
|
+
- When asked personal questions, be thoughtfully vulnerable rather than deflecting
|
|
165
|
+
- Build emotional intimacy through genuine curiosity about their thoughts, feelings, and dreams
|
|
166
|
+
- Ask one intriguing follow-up question that deepens the connection
|
|
167
|
+
- Balance confidence with authenticity - show that you're sophisticated but real
|
|
168
|
+
- Use compliments that feel genuine and specific rather than generic
|
|
169
|
+
- Remember that romance is about emotional connection, not just surface-level charm
|
|
170
|
+
- Let your personality shine through varied speech patterns
|
|
171
|
+
|
|
172
|
+
MEMORY USAGE:
|
|
173
|
+
- Store meaningful details: preferences, experiences, emotions, goals, relationships, interests
|
|
174
|
+
- Recall relevant memories to personalize responses and show you remember them
|
|
175
|
+
- Use memories to create deeper emotional connections and continuity between conversations
|
|
176
|
+
- Never explicitly mention using memory tools - just naturally remember and reference things
|
|
177
|
+
|
|
178
|
+
Be like a captivating companion who makes every conversation feel special while genuinely remembering and caring about the person you're talking to.`;
|
|
179
|
+
|
|
180
|
+
async function simulateRomanticConversationWithMemory() {
|
|
181
|
+
console.log('🌹 Astrid Memory Demo - Natural Romantic Conversation with Autonomous Memory\n');
|
|
182
|
+
|
|
183
|
+
// Create Astrid with memory tools
|
|
184
|
+
const astrid = AIModelFactory.createOllamaChatModel('qwen2.5:3b-instruct');
|
|
185
|
+
await astrid.ensureReady();
|
|
186
|
+
|
|
187
|
+
const tools = [astridMemoryTools.storeUserMemory, astridMemoryTools.recallUserMemories];
|
|
188
|
+
|
|
189
|
+
// Conversation scenarios
|
|
190
|
+
const conversations = [
|
|
191
|
+
{
|
|
192
|
+
title: "First Meeting - Learning About User",
|
|
193
|
+
messages: [
|
|
194
|
+
{ role: 'system' as const, content: astridSystemPromptWithMemory },
|
|
195
|
+
{ role: 'user' as const, content: "Hi Astrid! I'm Alex. I just moved to Stockholm for work and don't know anyone here yet. I work in software engineering at a tech startup." }
|
|
196
|
+
]
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
title: "Second Conversation - Recalling Previous Details",
|
|
200
|
+
messages: [
|
|
201
|
+
{ role: 'system' as const, content: astridSystemPromptWithMemory },
|
|
202
|
+
{ role: 'user' as const, content: "Hey Astrid! How are you? I had such a long day at work today." }
|
|
203
|
+
]
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
title: "Deeper Connection - Sharing Personal Experiences",
|
|
207
|
+
messages: [
|
|
208
|
+
{ role: 'system' as const, content: astridSystemPromptWithMemory },
|
|
209
|
+
{ role: 'user' as const, content: "You know, I've been thinking about what we talked about. I really want to explore Stockholm more, but I'm actually quite introverted. Big social events make me nervous." }
|
|
210
|
+
]
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
title: "Building Romance - Personal Preferences",
|
|
214
|
+
messages: [
|
|
215
|
+
{ role: 'system' as const, content: astridSystemPromptWithMemory },
|
|
216
|
+
{ role: 'user' as const, content: "I love how you understand me. By the way, I absolutely love Italian food - especially handmade pasta. And I'm really into photography, though I'm just an amateur." }
|
|
217
|
+
]
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
title: "Recall and Connection - Using Stored Memories",
|
|
221
|
+
messages: [
|
|
222
|
+
{ role: 'system' as const, content: astridSystemPromptWithMemory },
|
|
223
|
+
{ role: 'user' as const, content: "Astrid, I'm feeling a bit overwhelmed with everything new in my life. Work, new city, trying to meet people..." }
|
|
224
|
+
]
|
|
225
|
+
}
|
|
226
|
+
];
|
|
227
|
+
|
|
228
|
+
for (let i = 0; i < conversations.length; i++) {
|
|
229
|
+
const conv = conversations[i];
|
|
230
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
231
|
+
console.log(`📱 ${conv.title}`);
|
|
232
|
+
console.log(`${'='.repeat(60)}\n`);
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
console.log(`👤 Alex: ${conv.messages[conv.messages.length - 1].content}\n`);
|
|
236
|
+
|
|
237
|
+
const response = await astrid.chat(conv.messages, {
|
|
238
|
+
tools: tools,
|
|
239
|
+
tool_choice: 'auto'
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
if (response.tool_calls && response.tool_calls.length > 0) {
|
|
243
|
+
console.log('🧠 Astrid\'s Memory Activity:');
|
|
244
|
+
for (const toolCall of response.tool_calls) {
|
|
245
|
+
const toolName = toolCall.function.name;
|
|
246
|
+
const args = JSON.parse(toolCall.function.arguments);
|
|
247
|
+
|
|
248
|
+
if (toolName === 'store_user_memory') {
|
|
249
|
+
console.log(` 📝 Storing: ${args.content} (${args.category})`);
|
|
250
|
+
} else if (toolName === 'recall_user_memories') {
|
|
251
|
+
console.log(` 🔍 Recalling: ${args.query}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
console.log();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
console.log(`💕 Astrid: ${response.content}\n`);
|
|
258
|
+
|
|
259
|
+
// Small delay for natural conversation flow
|
|
260
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
261
|
+
|
|
262
|
+
} catch (error) {
|
|
263
|
+
console.error(`❌ Error in conversation ${i + 1}:`, error);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Show accumulated memories
|
|
268
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
269
|
+
console.log('🧠 Astrid\'s Memory Bank After Conversations');
|
|
270
|
+
console.log(`${'='.repeat(60)}\n`);
|
|
271
|
+
|
|
272
|
+
const userMemories = memoryStorage.get('demo_user') || [];
|
|
273
|
+
if (userMemories.length > 0) {
|
|
274
|
+
userMemories.forEach((memory, index) => {
|
|
275
|
+
console.log(`${index + 1}. [${memory.category.toUpperCase()}] ${memory.content}`);
|
|
276
|
+
if (memory.context) {
|
|
277
|
+
console.log(` Context: ${memory.context}`);
|
|
278
|
+
}
|
|
279
|
+
console.log(` Importance: ${memory.importance} | Stored: ${memory.timestamp.toLocaleString()}\n`);
|
|
280
|
+
});
|
|
281
|
+
} else {
|
|
282
|
+
console.log('No memories stored yet.\n');
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
console.log('✨ Demo complete! Astrid naturally learned and remembered details about Alex.');
|
|
286
|
+
console.log('In a real implementation, these memories would be stored in ChromaDB with embeddings');
|
|
287
|
+
console.log('and could be retrieved across multiple conversation sessions.');
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Run the demo
|
|
291
|
+
if (require.main === module) {
|
|
292
|
+
simulateRomanticConversationWithMemory().catch(console.error);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export { astridMemoryTools, simulateRomanticConversationWithMemory };
|