@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.
Files changed (66) hide show
  1. package/dist/commands/db.d.ts.map +1 -1
  2. package/dist/commands/db.js +18 -6
  3. package/dist/commands/db.js.map +1 -1
  4. package/dist/commands/deploy.d.ts.map +1 -1
  5. package/dist/commands/deploy.js +74 -34
  6. package/dist/commands/deploy.js.map +1 -1
  7. package/dist/commands/dev.js +3 -2
  8. package/dist/commands/dev.js.map +1 -1
  9. package/dist/commands/init.d.ts.map +1 -1
  10. package/dist/commands/init.js +12 -0
  11. package/dist/commands/init.js.map +1 -1
  12. package/dist/types.d.ts +1 -1
  13. package/dist/types.d.ts.map +1 -1
  14. package/dist/utils/app-template-sync.d.ts.map +1 -1
  15. package/dist/utils/app-template-sync.js +3 -1
  16. package/dist/utils/app-template-sync.js.map +1 -1
  17. package/dist/utils/init/quickstart-setup.d.ts.map +1 -1
  18. package/dist/utils/init/quickstart-setup.js.map +1 -1
  19. package/package.json +4 -4
  20. package/templates/basic/.env.local.example +23 -0
  21. package/templates/basic/README.md +181 -56
  22. package/templates/basic/package-lock.json +2180 -406
  23. package/templates/basic/package.json +23 -5
  24. package/templates/basic/src/__tests__/chat.test.ts +340 -0
  25. package/templates/basic/src/__tests__/cortex.test.ts +260 -0
  26. package/templates/basic/src/__tests__/display.test.ts +455 -0
  27. package/templates/basic/src/__tests__/e2e/fact-extraction.test.ts +498 -0
  28. package/templates/basic/src/__tests__/e2e/memory-flow.test.ts +355 -0
  29. package/templates/basic/src/__tests__/e2e/server-e2e.test.ts +414 -0
  30. package/templates/basic/src/__tests__/helpers/test-utils.ts +345 -0
  31. package/templates/basic/src/__tests__/integration/chat-flow.test.ts +422 -0
  32. package/templates/basic/src/__tests__/integration/server.test.ts +441 -0
  33. package/templates/basic/src/__tests__/llm.test.ts +344 -0
  34. package/templates/basic/src/chat.ts +300 -0
  35. package/templates/basic/src/cortex.ts +203 -0
  36. package/templates/basic/src/display.ts +425 -0
  37. package/templates/basic/src/index.ts +194 -64
  38. package/templates/basic/src/llm.ts +214 -0
  39. package/templates/basic/src/server.ts +280 -0
  40. package/templates/basic/vitest.config.ts +33 -0
  41. package/templates/basic/vitest.e2e.config.ts +28 -0
  42. package/templates/basic/vitest.integration.config.ts +25 -0
  43. package/templates/vercel-ai-quickstart/app/api/auth/check/route.ts +1 -1
  44. package/templates/vercel-ai-quickstart/app/api/auth/login/route.ts +6 -9
  45. package/templates/vercel-ai-quickstart/app/api/auth/register/route.ts +14 -18
  46. package/templates/vercel-ai-quickstart/app/api/auth/setup/route.ts +4 -7
  47. package/templates/vercel-ai-quickstart/app/api/chat/route.ts +28 -11
  48. package/templates/vercel-ai-quickstart/app/api/chat-v6/route.ts +19 -13
  49. package/templates/vercel-ai-quickstart/app/api/conversations/route.ts +16 -16
  50. package/templates/vercel-ai-quickstart/app/globals.css +24 -9
  51. package/templates/vercel-ai-quickstart/app/page.tsx +25 -13
  52. package/templates/vercel-ai-quickstart/components/AdminSetup.tsx +3 -1
  53. package/templates/vercel-ai-quickstart/components/AuthProvider.tsx +6 -6
  54. package/templates/vercel-ai-quickstart/components/ChatHistorySidebar.tsx +19 -8
  55. package/templates/vercel-ai-quickstart/components/ChatInterface.tsx +41 -14
  56. package/templates/vercel-ai-quickstart/components/LoginScreen.tsx +10 -5
  57. package/templates/vercel-ai-quickstart/lib/agents/memory-agent.ts +3 -3
  58. package/templates/vercel-ai-quickstart/lib/password.ts +5 -5
  59. package/templates/vercel-ai-quickstart/next.config.js +10 -2
  60. package/templates/vercel-ai-quickstart/package.json +18 -11
  61. package/templates/vercel-ai-quickstart/test-api.mjs +131 -100
  62. package/templates/vercel-ai-quickstart/tests/e2e/chat-memory-flow.test.ts +73 -44
  63. package/templates/vercel-ai-quickstart/tests/helpers/mock-cortex.ts +40 -40
  64. package/templates/vercel-ai-quickstart/tests/integration/auth.test.ts +8 -8
  65. package/templates/vercel-ai-quickstart/tests/integration/conversations.test.ts +12 -8
  66. 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 || 'http://localhost:3000';
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 = 'quickstart-demo';
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${'='.repeat(60)}`);
18
+ console.log(`\n${"=".repeat(60)}`);
19
19
  console.log(`Testing ${routeName} (${routePath})`);
20
- console.log('='.repeat(60));
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('\n📤 Test 1: Sending message with a fact...');
25
+ console.log("\n📤 Test 1: Sending message with a fact...");
26
26
  const message1 = {
27
27
  id: `msg-${Date.now()}-1`,
28
- role: 'user',
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: 'POST',
36
- headers: { 'Content-Type': 'application/json' },
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 { success: false, route: routeName, error: `HTTP ${response1.status}` };
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(`✅ Response received (${chunks} chunks, ${fullResponse.length} bytes)`);
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 = fullResponse.includes('FACTS_LAYER') ||
70
- fullResponse.includes('MEMORY_LAYER') ||
71
- fullResponse.includes('layerId');
72
- console.log(` Layer observer data: ${hasLayerData ? '✅ Present' : '❌ Missing'}`);
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 = fullResponse.includes('"type":"text"') ||
76
- fullResponse.includes('text-delta');
77
- console.log(` Text content: ${hasTextContent ? '✅ Present' : '❌ Missing'}`);
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('\n⏳ Waiting for memory processing...');
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('\n🔍 Test 2: Checking stored facts...');
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: 'GET' }
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(`✅ Facts API returned: ${Array.isArray(facts) ? facts.length : 'unknown'} facts`);
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(' Sample facts:');
115
+ console.log(" Sample facts:");
103
116
  facts.slice(0, 3).forEach((fact, i) => {
104
- const content = fact.content || fact.text || JSON.stringify(fact).slice(0, 100);
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('\n📤 Test 3: Sending follow-up to test recall...');
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: 'user',
120
- content: 'What programming language do I prefer?',
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: 'assistant',
128
- content: 'Great! TypeScript is a fantastic choice for type-safe development.',
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: 'POST',
135
- headers: { 'Content-Type': 'application/json' },
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(`❌ Follow-up request failed with status ${response2.status}`);
146
- return { success: false, route: routeName, error: `Follow-up HTTP ${response2.status}` };
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.toLowerCase().includes('typescript');
181
+ const mentionsTypeScript = fullResponse
182
+ .toLowerCase()
183
+ .includes("typescript");
161
184
  console.log(`✅ Response received`);
162
- console.log(` Recalls TypeScript preference: ${mentionsTypeScript ? '✅ Yes' : '❌ No'}`);
163
-
164
- return {
165
- success: true,
166
- route: routeName,
167
- recallWorks: mentionsTypeScript
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${'='.repeat(60)}`);
178
- console.log('Testing Conversation API');
179
- console.log('='.repeat(60));
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: 'GET' }
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(`✅ Conversations API works: ${Array.isArray(conversations) ? conversations.length : 'unknown'} conversations`);
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('🏥 Checking server health...');
229
+ console.log("🏥 Checking server health...");
204
230
  try {
205
- const response = await fetch(`${BASE_URL}/api/health`, {
206
- method: 'GET',
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('✅ Server is healthy');
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('🧪 Cortex Memory API Route Tests');
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('\n❌ Server is not running. Please start the quickstart first:');
232
- console.log(' cd packages/vercel-ai-provider/quickstart && npm run dev');
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('/api/chat', 'V5 Route');
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('/api/chat-v6', 'V6 Route');
274
+ const v6Result = await testRoute("/api/chat-v6", "V6 Route");
247
275
  results.push(v6Result);
248
-
276
+
249
277
  // Summary
250
- console.log(`\n${'='.repeat(60)}`);
251
- console.log('📊 Test Summary');
252
- console.log('='.repeat(60));
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 ? '✅ PASS' : '❌ FAIL';
257
- const recall = result.recallWorks !== undefined
258
- ? (result.recallWorks ? ' (recall ✅)' : ' (recall ❌)')
259
- : '';
260
- const error = result.error ? ` - ${result.error}` : '';
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('Test runner error:', 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
- [{ role: "user", content: "My name is Alice and I work as a software engineer" }],
144
- { userId: testUserId, memorySpaceId: testMemorySpaceId }
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
- { role: "assistant", content: "Got it, blue is your favorite color!" },
179
- { role: "user", content: "Actually, my favorite color is purple now" },
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(`[V5] All facts: ${allFacts.length}, Active: ${activeFacts.length}`);
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(`[V5] Recall response: ${conv2Result.response.slice(0, 200)}...`);
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 = responseText.includes("max") || responseText.includes("dog");
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
- { role: "user", content: "Actually I've switched to coffee now, it helps me focus" },
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(`[V6] All facts: ${allFacts.length}, Active: ${activeFacts.length}`);
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(`[V6] Recall response: ${conv2Result.response.slice(0, 200)}...`);
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
- "chat",
365
- [{ role: "user", content: message }],
366
- { userId: v5UserId, memorySpaceId: sharedSpaceId }
367
- ),
368
- sendChatMessage(
369
- "chat-v6",
370
- [{ role: "user", content: message }],
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("V5 facts:", v5Facts.map((f) => f.fact));
394
- console.log("V6 facts:", v6Facts.map((f) => f.fact));
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(`Conversations: ${JSON.stringify(listData.conversations, null, 2)}`);
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
  });