@cortexmemory/cli 0.27.4 → 0.28.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/commands/db.d.ts.map +1 -1
- package/dist/commands/db.js +18 -6
- package/dist/commands/db.js.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +74 -34
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.js +3 -2
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +12 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/app-template-sync.d.ts.map +1 -1
- package/dist/utils/app-template-sync.js +3 -1
- package/dist/utils/app-template-sync.js.map +1 -1
- package/dist/utils/init/quickstart-setup.d.ts.map +1 -1
- package/dist/utils/init/quickstart-setup.js.map +1 -1
- package/package.json +4 -4
- package/templates/basic/.env.local.example +23 -0
- package/templates/basic/README.md +181 -56
- package/templates/basic/package-lock.json +2180 -406
- package/templates/basic/package.json +23 -5
- package/templates/basic/src/__tests__/chat.test.ts +340 -0
- package/templates/basic/src/__tests__/cortex.test.ts +260 -0
- package/templates/basic/src/__tests__/display.test.ts +455 -0
- package/templates/basic/src/__tests__/e2e/fact-extraction.test.ts +498 -0
- package/templates/basic/src/__tests__/e2e/memory-flow.test.ts +355 -0
- package/templates/basic/src/__tests__/e2e/server-e2e.test.ts +414 -0
- package/templates/basic/src/__tests__/helpers/test-utils.ts +345 -0
- package/templates/basic/src/__tests__/integration/chat-flow.test.ts +422 -0
- package/templates/basic/src/__tests__/integration/server.test.ts +441 -0
- package/templates/basic/src/__tests__/llm.test.ts +344 -0
- package/templates/basic/src/chat.ts +300 -0
- package/templates/basic/src/cortex.ts +203 -0
- package/templates/basic/src/display.ts +425 -0
- package/templates/basic/src/index.ts +194 -64
- package/templates/basic/src/llm.ts +214 -0
- package/templates/basic/src/server.ts +280 -0
- package/templates/basic/vitest.config.ts +33 -0
- package/templates/basic/vitest.e2e.config.ts +28 -0
- package/templates/basic/vitest.integration.config.ts +25 -0
- package/templates/vercel-ai-quickstart/app/api/auth/check/route.ts +1 -1
- package/templates/vercel-ai-quickstart/app/api/auth/login/route.ts +6 -9
- package/templates/vercel-ai-quickstart/app/api/auth/register/route.ts +14 -18
- package/templates/vercel-ai-quickstart/app/api/auth/setup/route.ts +4 -7
- package/templates/vercel-ai-quickstart/app/api/chat/route.ts +28 -11
- package/templates/vercel-ai-quickstart/app/api/chat-v6/route.ts +19 -13
- package/templates/vercel-ai-quickstart/app/api/conversations/route.ts +16 -16
- package/templates/vercel-ai-quickstart/app/globals.css +24 -9
- package/templates/vercel-ai-quickstart/app/page.tsx +25 -13
- package/templates/vercel-ai-quickstart/components/AdminSetup.tsx +3 -1
- package/templates/vercel-ai-quickstart/components/AuthProvider.tsx +6 -6
- package/templates/vercel-ai-quickstart/components/ChatHistorySidebar.tsx +19 -8
- package/templates/vercel-ai-quickstart/components/ChatInterface.tsx +41 -14
- package/templates/vercel-ai-quickstart/components/LoginScreen.tsx +10 -5
- package/templates/vercel-ai-quickstart/lib/agents/memory-agent.ts +3 -3
- package/templates/vercel-ai-quickstart/lib/password.ts +5 -5
- package/templates/vercel-ai-quickstart/next.config.js +10 -2
- package/templates/vercel-ai-quickstart/package.json +18 -11
- package/templates/vercel-ai-quickstart/test-api.mjs +131 -100
- package/templates/vercel-ai-quickstart/tests/e2e/chat-memory-flow.test.ts +73 -44
- package/templates/vercel-ai-quickstart/tests/helpers/mock-cortex.ts +40 -40
- package/templates/vercel-ai-quickstart/tests/integration/auth.test.ts +8 -8
- package/templates/vercel-ai-quickstart/tests/integration/conversations.test.ts +12 -8
- package/templates/vercel-ai-quickstart/tests/unit/password.test.ts +4 -1
|
@@ -4,36 +4,36 @@
|
|
|
4
4
|
* Tests both v5 and v6 routes for memory functionality
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const BASE_URL = process.env.QUICKSTART_URL ||
|
|
7
|
+
const BASE_URL = process.env.QUICKSTART_URL || "http://localhost:3000";
|
|
8
8
|
|
|
9
9
|
// Test configuration
|
|
10
10
|
const TEST_USER_ID = `test-user-${Date.now()}`;
|
|
11
|
-
const TEST_MEMORY_SPACE_ID =
|
|
11
|
+
const TEST_MEMORY_SPACE_ID = "quickstart-demo";
|
|
12
12
|
|
|
13
13
|
async function sleep(ms) {
|
|
14
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
14
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
async function testRoute(routePath, routeName) {
|
|
18
|
-
console.log(`\n${
|
|
18
|
+
console.log(`\n${"=".repeat(60)}`);
|
|
19
19
|
console.log(`Testing ${routeName} (${routePath})`);
|
|
20
|
-
console.log(
|
|
21
|
-
|
|
20
|
+
console.log("=".repeat(60));
|
|
21
|
+
|
|
22
22
|
const conversationId = `conv-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
// Test 1: Send a message with a fact
|
|
25
|
-
console.log(
|
|
25
|
+
console.log("\n📤 Test 1: Sending message with a fact...");
|
|
26
26
|
const message1 = {
|
|
27
27
|
id: `msg-${Date.now()}-1`,
|
|
28
|
-
role:
|
|
28
|
+
role: "user",
|
|
29
29
|
content: `My favorite programming language is TypeScript and I work at a company called TechCorp.`,
|
|
30
30
|
createdAt: new Date().toISOString(),
|
|
31
31
|
};
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
try {
|
|
34
34
|
const response1 = await fetch(`${BASE_URL}${routePath}`, {
|
|
35
|
-
method:
|
|
36
|
-
headers: {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: { "Content-Type": "application/json" },
|
|
37
37
|
body: JSON.stringify({
|
|
38
38
|
messages: [message1],
|
|
39
39
|
userId: TEST_USER_ID,
|
|
@@ -41,20 +41,24 @@ async function testRoute(routePath, routeName) {
|
|
|
41
41
|
conversationId,
|
|
42
42
|
}),
|
|
43
43
|
});
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
if (!response1.ok) {
|
|
46
46
|
const errorText = await response1.text();
|
|
47
47
|
console.log(`❌ Request failed with status ${response1.status}`);
|
|
48
48
|
console.log(` Error: ${errorText.slice(0, 500)}`);
|
|
49
|
-
return {
|
|
49
|
+
return {
|
|
50
|
+
success: false,
|
|
51
|
+
route: routeName,
|
|
52
|
+
error: `HTTP ${response1.status}`,
|
|
53
|
+
};
|
|
50
54
|
}
|
|
51
|
-
|
|
55
|
+
|
|
52
56
|
// Read streaming response
|
|
53
57
|
const reader = response1.body.getReader();
|
|
54
58
|
const decoder = new TextDecoder();
|
|
55
|
-
let fullResponse =
|
|
59
|
+
let fullResponse = "";
|
|
56
60
|
let chunks = 0;
|
|
57
|
-
|
|
61
|
+
|
|
58
62
|
while (true) {
|
|
59
63
|
const { done, value } = await reader.read();
|
|
60
64
|
if (done) break;
|
|
@@ -62,46 +66,56 @@ async function testRoute(routePath, routeName) {
|
|
|
62
66
|
fullResponse += chunk;
|
|
63
67
|
chunks++;
|
|
64
68
|
}
|
|
65
|
-
|
|
66
|
-
console.log(
|
|
67
|
-
|
|
69
|
+
|
|
70
|
+
console.log(
|
|
71
|
+
`✅ Response received (${chunks} chunks, ${fullResponse.length} bytes)`,
|
|
72
|
+
);
|
|
73
|
+
|
|
68
74
|
// Check for layer observer data
|
|
69
|
-
const hasLayerData =
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
const hasLayerData =
|
|
76
|
+
fullResponse.includes("FACTS_LAYER") ||
|
|
77
|
+
fullResponse.includes("MEMORY_LAYER") ||
|
|
78
|
+
fullResponse.includes("layerId");
|
|
79
|
+
console.log(
|
|
80
|
+
` Layer observer data: ${hasLayerData ? "✅ Present" : "❌ Missing"}`,
|
|
81
|
+
);
|
|
82
|
+
|
|
74
83
|
// Check for text content
|
|
75
|
-
const hasTextContent =
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
84
|
+
const hasTextContent =
|
|
85
|
+
fullResponse.includes('"type":"text"') ||
|
|
86
|
+
fullResponse.includes("text-delta");
|
|
87
|
+
console.log(
|
|
88
|
+
` Text content: ${hasTextContent ? "✅ Present" : "❌ Missing"}`,
|
|
89
|
+
);
|
|
79
90
|
} catch (error) {
|
|
80
91
|
console.log(`❌ Request error: ${error.message}`);
|
|
81
92
|
return { success: false, route: routeName, error: error.message };
|
|
82
93
|
}
|
|
83
|
-
|
|
94
|
+
|
|
84
95
|
// Wait for async processing (fact extraction, etc.)
|
|
85
|
-
console.log(
|
|
96
|
+
console.log("\n⏳ Waiting for memory processing...");
|
|
86
97
|
await sleep(3000);
|
|
87
|
-
|
|
98
|
+
|
|
88
99
|
// Test 2: Check if facts were stored
|
|
89
|
-
console.log(
|
|
100
|
+
console.log("\n🔍 Test 2: Checking stored facts...");
|
|
90
101
|
try {
|
|
91
102
|
const factsResponse = await fetch(
|
|
92
103
|
`${BASE_URL}/api/facts?userId=${TEST_USER_ID}&memorySpaceId=${TEST_MEMORY_SPACE_ID}`,
|
|
93
|
-
{ method:
|
|
104
|
+
{ method: "GET" },
|
|
94
105
|
);
|
|
95
|
-
|
|
106
|
+
|
|
96
107
|
if (factsResponse.ok) {
|
|
97
108
|
const factsData = await factsResponse.json();
|
|
98
109
|
const facts = factsData.facts || factsData || [];
|
|
99
|
-
console.log(
|
|
100
|
-
|
|
110
|
+
console.log(
|
|
111
|
+
`✅ Facts API returned: ${Array.isArray(facts) ? facts.length : "unknown"} facts`,
|
|
112
|
+
);
|
|
113
|
+
|
|
101
114
|
if (Array.isArray(facts) && facts.length > 0) {
|
|
102
|
-
console.log(
|
|
115
|
+
console.log(" Sample facts:");
|
|
103
116
|
facts.slice(0, 3).forEach((fact, i) => {
|
|
104
|
-
const content =
|
|
117
|
+
const content =
|
|
118
|
+
fact.content || fact.text || JSON.stringify(fact).slice(0, 100);
|
|
105
119
|
console.log(` ${i + 1}. ${content.slice(0, 80)}...`);
|
|
106
120
|
});
|
|
107
121
|
}
|
|
@@ -111,28 +125,29 @@ async function testRoute(routePath, routeName) {
|
|
|
111
125
|
} catch (error) {
|
|
112
126
|
console.log(`⚠️ Could not check facts: ${error.message}`);
|
|
113
127
|
}
|
|
114
|
-
|
|
128
|
+
|
|
115
129
|
// Test 3: Send follow-up message and verify recall
|
|
116
|
-
console.log(
|
|
130
|
+
console.log("\n📤 Test 3: Sending follow-up to test recall...");
|
|
117
131
|
const message2 = {
|
|
118
132
|
id: `msg-${Date.now()}-2`,
|
|
119
|
-
role:
|
|
120
|
-
content:
|
|
133
|
+
role: "user",
|
|
134
|
+
content: "What programming language do I prefer?",
|
|
121
135
|
createdAt: new Date().toISOString(),
|
|
122
136
|
};
|
|
123
|
-
|
|
137
|
+
|
|
124
138
|
// Include previous assistant response for context
|
|
125
139
|
const message1Response = {
|
|
126
140
|
id: `msg-${Date.now()}-1r`,
|
|
127
|
-
role:
|
|
128
|
-
content:
|
|
141
|
+
role: "assistant",
|
|
142
|
+
content:
|
|
143
|
+
"Great! TypeScript is a fantastic choice for type-safe development.",
|
|
129
144
|
createdAt: new Date().toISOString(),
|
|
130
145
|
};
|
|
131
|
-
|
|
146
|
+
|
|
132
147
|
try {
|
|
133
148
|
const response2 = await fetch(`${BASE_URL}${routePath}`, {
|
|
134
|
-
method:
|
|
135
|
-
headers: {
|
|
149
|
+
method: "POST",
|
|
150
|
+
headers: { "Content-Type": "application/json" },
|
|
136
151
|
body: JSON.stringify({
|
|
137
152
|
messages: [message1, message1Response, message2],
|
|
138
153
|
userId: TEST_USER_ID,
|
|
@@ -140,33 +155,42 @@ async function testRoute(routePath, routeName) {
|
|
|
140
155
|
conversationId,
|
|
141
156
|
}),
|
|
142
157
|
});
|
|
143
|
-
|
|
158
|
+
|
|
144
159
|
if (!response2.ok) {
|
|
145
|
-
console.log(
|
|
146
|
-
|
|
160
|
+
console.log(
|
|
161
|
+
`❌ Follow-up request failed with status ${response2.status}`,
|
|
162
|
+
);
|
|
163
|
+
return {
|
|
164
|
+
success: false,
|
|
165
|
+
route: routeName,
|
|
166
|
+
error: `Follow-up HTTP ${response2.status}`,
|
|
167
|
+
};
|
|
147
168
|
}
|
|
148
|
-
|
|
169
|
+
|
|
149
170
|
const reader = response2.body.getReader();
|
|
150
171
|
const decoder = new TextDecoder();
|
|
151
|
-
let fullResponse =
|
|
152
|
-
|
|
172
|
+
let fullResponse = "";
|
|
173
|
+
|
|
153
174
|
while (true) {
|
|
154
175
|
const { done, value } = await reader.read();
|
|
155
176
|
if (done) break;
|
|
156
177
|
fullResponse += decoder.decode(value, { stream: true });
|
|
157
178
|
}
|
|
158
|
-
|
|
179
|
+
|
|
159
180
|
// Check if TypeScript was mentioned in the response (recall working)
|
|
160
|
-
const mentionsTypeScript = fullResponse
|
|
181
|
+
const mentionsTypeScript = fullResponse
|
|
182
|
+
.toLowerCase()
|
|
183
|
+
.includes("typescript");
|
|
161
184
|
console.log(`✅ Response received`);
|
|
162
|
-
console.log(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
185
|
+
console.log(
|
|
186
|
+
` Recalls TypeScript preference: ${mentionsTypeScript ? "✅ Yes" : "❌ No"}`,
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
success: true,
|
|
191
|
+
route: routeName,
|
|
192
|
+
recallWorks: mentionsTypeScript,
|
|
168
193
|
};
|
|
169
|
-
|
|
170
194
|
} catch (error) {
|
|
171
195
|
console.log(`❌ Follow-up request error: ${error.message}`);
|
|
172
196
|
return { success: false, route: routeName, error: error.message };
|
|
@@ -174,20 +198,22 @@ async function testRoute(routePath, routeName) {
|
|
|
174
198
|
}
|
|
175
199
|
|
|
176
200
|
async function testConversationAPI() {
|
|
177
|
-
console.log(`\n${
|
|
178
|
-
console.log(
|
|
179
|
-
console.log(
|
|
180
|
-
|
|
201
|
+
console.log(`\n${"=".repeat(60)}`);
|
|
202
|
+
console.log("Testing Conversation API");
|
|
203
|
+
console.log("=".repeat(60));
|
|
204
|
+
|
|
181
205
|
try {
|
|
182
206
|
const response = await fetch(
|
|
183
207
|
`${BASE_URL}/api/conversations?userId=${TEST_USER_ID}&memorySpaceId=${TEST_MEMORY_SPACE_ID}`,
|
|
184
|
-
{ method:
|
|
208
|
+
{ method: "GET" },
|
|
185
209
|
);
|
|
186
|
-
|
|
210
|
+
|
|
187
211
|
if (response.ok) {
|
|
188
212
|
const data = await response.json();
|
|
189
213
|
const conversations = data.conversations || data || [];
|
|
190
|
-
console.log(
|
|
214
|
+
console.log(
|
|
215
|
+
`✅ Conversations API works: ${Array.isArray(conversations) ? conversations.length : "unknown"} conversations`,
|
|
216
|
+
);
|
|
191
217
|
return true;
|
|
192
218
|
} else {
|
|
193
219
|
console.log(`❌ Conversations API returned ${response.status}`);
|
|
@@ -200,14 +226,14 @@ async function testConversationAPI() {
|
|
|
200
226
|
}
|
|
201
227
|
|
|
202
228
|
async function checkServerHealth() {
|
|
203
|
-
console.log(
|
|
229
|
+
console.log("🏥 Checking server health...");
|
|
204
230
|
try {
|
|
205
|
-
const response = await fetch(`${BASE_URL}/api/health`, {
|
|
206
|
-
method:
|
|
207
|
-
signal: AbortSignal.timeout(5000)
|
|
231
|
+
const response = await fetch(`${BASE_URL}/api/health`, {
|
|
232
|
+
method: "GET",
|
|
233
|
+
signal: AbortSignal.timeout(5000),
|
|
208
234
|
});
|
|
209
235
|
if (response.ok) {
|
|
210
|
-
console.log(
|
|
236
|
+
console.log("✅ Server is healthy");
|
|
211
237
|
return true;
|
|
212
238
|
} else {
|
|
213
239
|
console.log(`❌ Health check failed: ${response.status}`);
|
|
@@ -220,53 +246,58 @@ async function checkServerHealth() {
|
|
|
220
246
|
}
|
|
221
247
|
|
|
222
248
|
async function main() {
|
|
223
|
-
console.log(
|
|
249
|
+
console.log("🧪 Cortex Memory API Route Tests");
|
|
224
250
|
console.log(`📍 Testing server at: ${BASE_URL}`);
|
|
225
251
|
console.log(`👤 Test user: ${TEST_USER_ID}`);
|
|
226
252
|
console.log(`📦 Memory space: ${TEST_MEMORY_SPACE_ID}`);
|
|
227
|
-
|
|
253
|
+
|
|
228
254
|
// Check server health first
|
|
229
255
|
const healthy = await checkServerHealth();
|
|
230
256
|
if (!healthy) {
|
|
231
|
-
console.log(
|
|
232
|
-
|
|
257
|
+
console.log(
|
|
258
|
+
"\n❌ Server is not running. Please start the quickstart first:",
|
|
259
|
+
);
|
|
260
|
+
console.log(" cd packages/vercel-ai-provider/quickstart && npm run dev");
|
|
233
261
|
process.exit(1);
|
|
234
262
|
}
|
|
235
|
-
|
|
263
|
+
|
|
236
264
|
const results = [];
|
|
237
|
-
|
|
265
|
+
|
|
238
266
|
// Test conversation API
|
|
239
267
|
await testConversationAPI();
|
|
240
|
-
|
|
268
|
+
|
|
241
269
|
// Test v5 route
|
|
242
|
-
const v5Result = await testRoute(
|
|
270
|
+
const v5Result = await testRoute("/api/chat", "V5 Route");
|
|
243
271
|
results.push(v5Result);
|
|
244
|
-
|
|
272
|
+
|
|
245
273
|
// Test v6 route
|
|
246
|
-
const v6Result = await testRoute(
|
|
274
|
+
const v6Result = await testRoute("/api/chat-v6", "V6 Route");
|
|
247
275
|
results.push(v6Result);
|
|
248
|
-
|
|
276
|
+
|
|
249
277
|
// Summary
|
|
250
|
-
console.log(`\n${
|
|
251
|
-
console.log(
|
|
252
|
-
console.log(
|
|
253
|
-
|
|
278
|
+
console.log(`\n${"=".repeat(60)}`);
|
|
279
|
+
console.log("📊 Test Summary");
|
|
280
|
+
console.log("=".repeat(60));
|
|
281
|
+
|
|
254
282
|
let allPassed = true;
|
|
255
283
|
for (const result of results) {
|
|
256
|
-
const status = result.success ?
|
|
257
|
-
const recall =
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
284
|
+
const status = result.success ? "✅ PASS" : "❌ FAIL";
|
|
285
|
+
const recall =
|
|
286
|
+
result.recallWorks !== undefined
|
|
287
|
+
? result.recallWorks
|
|
288
|
+
? " (recall ✅)"
|
|
289
|
+
: " (recall ❌)"
|
|
290
|
+
: "";
|
|
291
|
+
const error = result.error ? ` - ${result.error}` : "";
|
|
261
292
|
console.log(`${status} ${result.route}${recall}${error}`);
|
|
262
293
|
if (!result.success) allPassed = false;
|
|
263
294
|
}
|
|
264
|
-
|
|
265
|
-
console.log(
|
|
295
|
+
|
|
296
|
+
console.log("");
|
|
266
297
|
process.exit(allPassed ? 0 : 1);
|
|
267
298
|
}
|
|
268
299
|
|
|
269
|
-
main().catch(error => {
|
|
270
|
-
console.error(
|
|
300
|
+
main().catch((error) => {
|
|
301
|
+
console.error("Test runner error:", error);
|
|
271
302
|
process.exit(1);
|
|
272
303
|
});
|
|
@@ -43,7 +43,7 @@ async function sendChatMessage(
|
|
|
43
43
|
userId: string;
|
|
44
44
|
memorySpaceId: string;
|
|
45
45
|
conversationId?: string;
|
|
46
|
-
}
|
|
46
|
+
},
|
|
47
47
|
): Promise<{
|
|
48
48
|
response: string;
|
|
49
49
|
conversationId?: string;
|
|
@@ -71,11 +71,11 @@ async function sendChatMessage(
|
|
|
71
71
|
|
|
72
72
|
// Parse streaming response
|
|
73
73
|
const text = await response.text();
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
// Extract text content from the stream (simplified parsing)
|
|
76
76
|
let fullResponse = "";
|
|
77
77
|
let conversationId: string | undefined;
|
|
78
|
-
|
|
78
|
+
|
|
79
79
|
const lines = text.split("\n");
|
|
80
80
|
for (const line of lines) {
|
|
81
81
|
if (line.startsWith("0:")) {
|
|
@@ -112,7 +112,7 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
112
112
|
beforeAll(() => {
|
|
113
113
|
if (SKIP_E2E) {
|
|
114
114
|
console.log(
|
|
115
|
-
"Skipping E2E tests - CONVEX_URL, OPENAI_API_KEY, or QUICKSTART_URL not configured"
|
|
115
|
+
"Skipping E2E tests - CONVEX_URL, OPENAI_API_KEY, or QUICKSTART_URL not configured",
|
|
116
116
|
);
|
|
117
117
|
return;
|
|
118
118
|
}
|
|
@@ -140,8 +140,13 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
140
140
|
// Send a message with a fact
|
|
141
141
|
await sendChatMessage(
|
|
142
142
|
"chat",
|
|
143
|
-
[
|
|
144
|
-
|
|
143
|
+
[
|
|
144
|
+
{
|
|
145
|
+
role: "user",
|
|
146
|
+
content: "My name is Alice and I work as a software engineer",
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
{ userId: testUserId, memorySpaceId: testMemorySpaceId },
|
|
145
150
|
);
|
|
146
151
|
|
|
147
152
|
// Wait for fact extraction
|
|
@@ -165,7 +170,7 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
165
170
|
await sendChatMessage(
|
|
166
171
|
"chat",
|
|
167
172
|
[{ role: "user", content: "My favorite color is blue" }],
|
|
168
|
-
{ userId: testUserId, memorySpaceId: testMemorySpaceId }
|
|
173
|
+
{ userId: testUserId, memorySpaceId: testMemorySpaceId },
|
|
169
174
|
);
|
|
170
175
|
|
|
171
176
|
await new Promise((r) => setTimeout(r, 5000));
|
|
@@ -175,10 +180,16 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
175
180
|
"chat",
|
|
176
181
|
[
|
|
177
182
|
{ role: "user", content: "My favorite color is blue" },
|
|
178
|
-
{
|
|
179
|
-
|
|
183
|
+
{
|
|
184
|
+
role: "assistant",
|
|
185
|
+
content: "Got it, blue is your favorite color!",
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
role: "user",
|
|
189
|
+
content: "Actually, my favorite color is purple now",
|
|
190
|
+
},
|
|
180
191
|
],
|
|
181
|
-
{ userId: testUserId, memorySpaceId: testMemorySpaceId }
|
|
192
|
+
{ userId: testUserId, memorySpaceId: testMemorySpaceId },
|
|
182
193
|
);
|
|
183
194
|
|
|
184
195
|
await new Promise((r) => setTimeout(r, 5000));
|
|
@@ -196,7 +207,9 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
196
207
|
includeSuperseded: false,
|
|
197
208
|
});
|
|
198
209
|
|
|
199
|
-
console.log(
|
|
210
|
+
console.log(
|
|
211
|
+
`[V5] All facts: ${allFacts.length}, Active: ${activeFacts.length}`,
|
|
212
|
+
);
|
|
200
213
|
allFacts.forEach((f) => {
|
|
201
214
|
const status = f.supersededBy ? "SUPERSEDED" : "ACTIVE";
|
|
202
215
|
console.log(` [${status}] ${f.fact}`);
|
|
@@ -207,7 +220,7 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
207
220
|
(f) =>
|
|
208
221
|
f.fact.toLowerCase().includes("color") ||
|
|
209
222
|
f.fact.toLowerCase().includes("purple") ||
|
|
210
|
-
f.fact.toLowerCase().includes("blue")
|
|
223
|
+
f.fact.toLowerCase().includes("blue"),
|
|
211
224
|
);
|
|
212
225
|
|
|
213
226
|
// Ideally only one active color fact (purple)
|
|
@@ -219,7 +232,7 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
219
232
|
const conv1Result = await sendChatMessage(
|
|
220
233
|
"chat",
|
|
221
234
|
[{ role: "user", content: "I have a dog named Max" }],
|
|
222
|
-
{ userId: testUserId, memorySpaceId: testMemorySpaceId }
|
|
235
|
+
{ userId: testUserId, memorySpaceId: testMemorySpaceId },
|
|
223
236
|
);
|
|
224
237
|
|
|
225
238
|
await new Promise((r) => setTimeout(r, 5000));
|
|
@@ -228,15 +241,18 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
228
241
|
const conv2Result = await sendChatMessage(
|
|
229
242
|
"chat",
|
|
230
243
|
[{ role: "user", content: "What do you remember about my pets?" }],
|
|
231
|
-
{ userId: testUserId, memorySpaceId: testMemorySpaceId }
|
|
244
|
+
{ userId: testUserId, memorySpaceId: testMemorySpaceId },
|
|
232
245
|
);
|
|
233
246
|
|
|
234
|
-
console.log(
|
|
247
|
+
console.log(
|
|
248
|
+
`[V5] Recall response: ${conv2Result.response.slice(0, 200)}...`,
|
|
249
|
+
);
|
|
235
250
|
|
|
236
251
|
// Response should mention Max (the dog)
|
|
237
252
|
const responseText = conv2Result.response.toLowerCase();
|
|
238
|
-
const mentionsPet =
|
|
239
|
-
|
|
253
|
+
const mentionsPet =
|
|
254
|
+
responseText.includes("max") || responseText.includes("dog");
|
|
255
|
+
|
|
240
256
|
// Note: LLM responses are non-deterministic, so we just verify we got a response
|
|
241
257
|
expect(conv2Result.response.length).toBeGreaterThan(0);
|
|
242
258
|
}, 90000);
|
|
@@ -252,7 +268,7 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
252
268
|
await sendChatMessage(
|
|
253
269
|
"chat-v6",
|
|
254
270
|
[{ role: "user", content: "My name is Bob and I'm a data scientist" }],
|
|
255
|
-
{ userId: testUserId, memorySpaceId: testMemorySpaceId }
|
|
271
|
+
{ userId: testUserId, memorySpaceId: testMemorySpaceId },
|
|
256
272
|
);
|
|
257
273
|
|
|
258
274
|
// Wait for fact extraction
|
|
@@ -276,7 +292,7 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
276
292
|
await sendChatMessage(
|
|
277
293
|
"chat-v6",
|
|
278
294
|
[{ role: "user", content: "I prefer tea over coffee" }],
|
|
279
|
-
{ userId: testUserId, memorySpaceId: testMemorySpaceId }
|
|
295
|
+
{ userId: testUserId, memorySpaceId: testMemorySpaceId },
|
|
280
296
|
);
|
|
281
297
|
|
|
282
298
|
await new Promise((r) => setTimeout(r, 5000));
|
|
@@ -287,9 +303,12 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
287
303
|
[
|
|
288
304
|
{ role: "user", content: "I prefer tea over coffee" },
|
|
289
305
|
{ role: "assistant", content: "Got it, you prefer tea!" },
|
|
290
|
-
{
|
|
306
|
+
{
|
|
307
|
+
role: "user",
|
|
308
|
+
content: "Actually I've switched to coffee now, it helps me focus",
|
|
309
|
+
},
|
|
291
310
|
],
|
|
292
|
-
{ userId: testUserId, memorySpaceId: testMemorySpaceId }
|
|
311
|
+
{ userId: testUserId, memorySpaceId: testMemorySpaceId },
|
|
293
312
|
);
|
|
294
313
|
|
|
295
314
|
await new Promise((r) => setTimeout(r, 5000));
|
|
@@ -307,7 +326,9 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
307
326
|
includeSuperseded: false,
|
|
308
327
|
});
|
|
309
328
|
|
|
310
|
-
console.log(
|
|
329
|
+
console.log(
|
|
330
|
+
`[V6] All facts: ${allFacts.length}, Active: ${activeFacts.length}`,
|
|
331
|
+
);
|
|
311
332
|
allFacts.forEach((f) => {
|
|
312
333
|
const status = f.supersededBy ? "SUPERSEDED" : "ACTIVE";
|
|
313
334
|
console.log(` [${status}] ${f.fact}`);
|
|
@@ -317,7 +338,7 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
317
338
|
const beverageFacts = allFacts.filter(
|
|
318
339
|
(f) =>
|
|
319
340
|
f.fact.toLowerCase().includes("tea") ||
|
|
320
|
-
f.fact.toLowerCase().includes("coffee")
|
|
341
|
+
f.fact.toLowerCase().includes("coffee"),
|
|
321
342
|
);
|
|
322
343
|
expect(beverageFacts.length).toBeGreaterThan(0);
|
|
323
344
|
}, 90000);
|
|
@@ -327,7 +348,7 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
327
348
|
await sendChatMessage(
|
|
328
349
|
"chat-v6",
|
|
329
350
|
[{ role: "user", content: "I live in San Francisco" }],
|
|
330
|
-
{ userId: testUserId, memorySpaceId: testMemorySpaceId }
|
|
351
|
+
{ userId: testUserId, memorySpaceId: testMemorySpaceId },
|
|
331
352
|
);
|
|
332
353
|
|
|
333
354
|
await new Promise((r) => setTimeout(r, 5000));
|
|
@@ -336,10 +357,12 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
336
357
|
const conv2Result = await sendChatMessage(
|
|
337
358
|
"chat-v6",
|
|
338
359
|
[{ role: "user", content: "Where do I live?" }],
|
|
339
|
-
{ userId: testUserId, memorySpaceId: testMemorySpaceId }
|
|
360
|
+
{ userId: testUserId, memorySpaceId: testMemorySpaceId },
|
|
340
361
|
);
|
|
341
362
|
|
|
342
|
-
console.log(
|
|
363
|
+
console.log(
|
|
364
|
+
`[V6] Recall response: ${conv2Result.response.slice(0, 200)}...`,
|
|
365
|
+
);
|
|
343
366
|
|
|
344
367
|
// Verify we got a response
|
|
345
368
|
expect(conv2Result.response.length).toBeGreaterThan(0);
|
|
@@ -360,16 +383,14 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
360
383
|
const message = "I am a TypeScript developer with 5 years of experience";
|
|
361
384
|
|
|
362
385
|
await Promise.all([
|
|
363
|
-
sendChatMessage(
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
{ userId: v6UserId, memorySpaceId: sharedSpaceId }
|
|
372
|
-
),
|
|
386
|
+
sendChatMessage("chat", [{ role: "user", content: message }], {
|
|
387
|
+
userId: v5UserId,
|
|
388
|
+
memorySpaceId: sharedSpaceId,
|
|
389
|
+
}),
|
|
390
|
+
sendChatMessage("chat-v6", [{ role: "user", content: message }], {
|
|
391
|
+
userId: v6UserId,
|
|
392
|
+
memorySpaceId: sharedSpaceId,
|
|
393
|
+
}),
|
|
373
394
|
]);
|
|
374
395
|
|
|
375
396
|
// Wait for fact extraction
|
|
@@ -390,8 +411,14 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
390
411
|
]);
|
|
391
412
|
|
|
392
413
|
console.log(`V5 facts: ${v5Facts.length}, V6 facts: ${v6Facts.length}`);
|
|
393
|
-
console.log(
|
|
394
|
-
|
|
414
|
+
console.log(
|
|
415
|
+
"V5 facts:",
|
|
416
|
+
v5Facts.map((f) => f.fact),
|
|
417
|
+
);
|
|
418
|
+
console.log(
|
|
419
|
+
"V6 facts:",
|
|
420
|
+
v6Facts.map((f) => f.fact),
|
|
421
|
+
);
|
|
395
422
|
|
|
396
423
|
// CRITICAL: Both routes should store facts
|
|
397
424
|
expect(v5Facts.length).toBeGreaterThan(0);
|
|
@@ -413,7 +440,7 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
413
440
|
const chatResult = await sendChatMessage(
|
|
414
441
|
"chat",
|
|
415
442
|
[{ role: "user", content: "Hello, this is a test conversation" }],
|
|
416
|
-
{ userId: testUserId, memorySpaceId: testMemorySpaceId }
|
|
443
|
+
{ userId: testUserId, memorySpaceId: testMemorySpaceId },
|
|
417
444
|
);
|
|
418
445
|
|
|
419
446
|
// Wait for conversation to be created
|
|
@@ -421,11 +448,13 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
421
448
|
|
|
422
449
|
// List conversations
|
|
423
450
|
const listResponse = await fetch(
|
|
424
|
-
`${BASE_URL}/api/conversations?userId=${testUserId}&memorySpaceId=${testMemorySpaceId}
|
|
451
|
+
`${BASE_URL}/api/conversations?userId=${testUserId}&memorySpaceId=${testMemorySpaceId}`,
|
|
425
452
|
);
|
|
426
453
|
const listData = await listResponse.json();
|
|
427
454
|
|
|
428
|
-
console.log(
|
|
455
|
+
console.log(
|
|
456
|
+
`Conversations: ${JSON.stringify(listData.conversations, null, 2)}`,
|
|
457
|
+
);
|
|
429
458
|
expect(listData.conversations).toBeDefined();
|
|
430
459
|
expect(listData.conversations.length).toBeGreaterThan(0);
|
|
431
460
|
|
|
@@ -433,7 +462,7 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
433
462
|
const convId = listData.conversations[0].id;
|
|
434
463
|
const deleteResponse = await fetch(
|
|
435
464
|
`${BASE_URL}/api/conversations?conversationId=${convId}`,
|
|
436
|
-
{ method: "DELETE" }
|
|
465
|
+
{ method: "DELETE" },
|
|
437
466
|
);
|
|
438
467
|
const deleteData = await deleteResponse.json();
|
|
439
468
|
|
|
@@ -441,13 +470,13 @@ describe("Chat Memory Flow E2E", () => {
|
|
|
441
470
|
|
|
442
471
|
// Verify deletion
|
|
443
472
|
const listAfterDelete = await fetch(
|
|
444
|
-
`${BASE_URL}/api/conversations?userId=${testUserId}&memorySpaceId=${testMemorySpaceId}
|
|
473
|
+
`${BASE_URL}/api/conversations?userId=${testUserId}&memorySpaceId=${testMemorySpaceId}`,
|
|
445
474
|
);
|
|
446
475
|
const listAfterDeleteData = await listAfterDelete.json();
|
|
447
476
|
|
|
448
477
|
// Should have one less conversation
|
|
449
478
|
expect(listAfterDeleteData.conversations.length).toBeLessThan(
|
|
450
|
-
listData.conversations.length
|
|
479
|
+
listData.conversations.length,
|
|
451
480
|
);
|
|
452
481
|
}, 60000);
|
|
453
482
|
});
|